nanobindを利用してPythonからC++の関数を使う(Windows, CMake, MSVC)

Programming
Programming
スポンサーリンク

はじめに

本記事には、以下の内容が含まれています。

  • C++実行環境の構築
  • nanobindを用いたPythonからのC++の関数の実行環境構築

対象環境はWindowsで、下記が私の環境です。

  • Windows 11 Home
  • VS Code (拡張機能: C/C++, CMake, CMake Toolsをインストール済)

事前準備(CMake, make, gccのインストールとC++の実行確認)

自分は普段Pythonしか書いていなくて、C++のビルド環境を構築するのにも手間取ったので、ここで合わせてまとめておきます。このあたりが詳しい方は、nanobindの設定の方に進んでください。

こちらに記載の通り下記の準備をしていきます。

  • CMake
  • Build Tools for Visual Studio 2022(MSVC)

CMakeのインストール

こちらから、Windows x64 Installer: cmake-3.28.0-rc5-windows-x86_64.msi をクリックして進めていきます。

Download CMake
You can either download binaries or source code archives for the latest stable or previous release or access the current...

手順は、こちらを参考にしました。

WindowsへのCMakeのインストール
「Cコンパイラをインストールしたい」「C++コンパイラをインストールしたい」 「WindowsにCMakeをインストールしたい」このような場合には、この記事の内容が参考になります。この記事では、WindowsへCMakeをインストールする方...

Build Tools for Visual Studio 2022(MSVC) のインストール

こちらからインストーラーをダウンロードできます。

Make for Windows
make {whatisit}

手順は、こちらを参考にしました。

make のインストール(Windows 上)
make のインストール(Windows 上)

C++の実行確認

ここまででC++のビルドに必要なツールはインストールし終えました。ここからは、一旦C++だけで実行ができる状態になっているかを確認していきます。

実行確認の前に、VSCodeのCMake Tools拡張機能の設定について、下記の3つの設定をしておきましょう。自動Configureする部分をfalseにしてます。後の方で拡張機能でConfigureすると、Pythonのパスがうまく取れなかったので全てfalseにしています。

  "cmake.configureOnOpen": false, // CMakeプロジェクトディレクトリを開いたときに自動でConfigure
  "cmake.configureOnEdit": false, // CMakeLists.txtの保存時に自動でConfigure
  "cmake.automaticReconfigure": false // 構成が変わったときに自動でConfigure

できたら、まずはプロジェクトディレクトリを作成し、カレントディレクトリを移動します。(今回はcmake-trialとします。)

下記のようにCMakeLists.txtを作成します。

cmake_minimum_required(VERSION 3.15)
project(cmake-trial LANGUAGES CXX)
add_executable(cmake-trial main.cpp)

また、main.cppも作成します。

#include <iostream>

int main(int, char**){
    std::cout << "Hello, from cmake-trial!\n";
}

ディレクトリ構成は下記のようになります。

cmake-trial
|   CMakeLists.txt
|   main.cpp

下記を順に実行していき、同じような出力が得られたらOKです。

> cmake -G "Visual Studio 17 2022" -S . -B build
-- The CXX compiler identification is MSVC 19.38.33130.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Tools/MSVC/14.38.33130/bin/Hostx64/x64/cl.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done (2.7s)
-- Generating done (0.0s)
-- Build files have been written to: <path-to-project>/cmake-trial/build

> cmake --build build --config Debug

MSBuild version 17.8.3+195e7f5a3 for .NET Framework

  1>Checking Build System
  Building Custom Rule <path-to-project>/cmake-trial/CMakeLists.txt
  main.cpp
  cmake-trial.vcxproj -> <path-to-project>\cmake-trial\build\Debug\
  cmake-trial.exe
  Building Custom Rule <path-to-project>/cmake-trial/CMakeLists.txt

> ./build/Debug/cmake-trial.exe
Hello, from cmake-trial!

ちなみに、少しだけコマンドの説明を書いておきます。(あまりわかっていない部分もあるので、間違いあれば随時修正します)

  • cmake -G “Visual Studio 17 2022” -S . -B build
    • -G: コンパイラの指定
    • -S: Sourceディレクトリ
    • -B: buildディレクトリ
  • cmake –build build –config Debug
    • –build: buildディレクトリ
    • –config: コンフィグモードの指定(Debug/Release/RelWithDebInfo/MinSizeRel?)

お疲れ様です。ここまでできたら、C++の実行環境は作れていると思います!

nanobindを使ってみる

nanobind とは

nanobind は、Python で C++ 型を公開したり、その逆を行う小さなバインディング ライブラリです。これはBoost.Pythonpybind11を彷彿とさせ、ほぼ同じ構文を使用します。これらの既存のツールとは対照的に、nanobind はより効率的です。バインディングはより短い時間でコンパイルされ、より小さなバイナリを生成し、実行時のパフォーマンスが向上します。

より具体的には、ベンチマークでは、pybind11 と比較して コンパイル時間が最大 4 倍速く、バイナリが最大 5 倍小さく、実行時のオーバーヘッドが最大10 倍低いことが示されています。nanobind は、重要な指標でも Cython よりも優れています (バイナリ サイズの3 ~ 12 倍の削減、コンパイル時間の1.6 ~ 4 倍の削減、同様のランタイム パフォーマンス)。

https://nanobind.readthedocs.io/en/latest/index.html

実際にnanobindを使ってみましょう!

下記を見ながら進めていきます。

Installing the library - nanobind documentation

まずは、プロジェクトディレクトリを作成します。今回は、 nanobind-test とします。poetryを使っている方は、 poetry new nanobind-test で、 nanobind-test プロジェクトを作成した後からスタートします。

nanobindのインストール

Installing the library を参考にします。推奨されているのはpipでのインストールですが、私はpoetryでパッケージ管理を行っているので、 poetry add でインストールしていきます。もし、venvなどで管理している方はpipでインストールして問題ないです。

poetry add nanobind

poetryの場合、下記のような出力が返ってきたらOKです。

Using version ^1.8.0 for nanobind

Updating dependencies
Resolving dependencies... (0.4s)

Package operations: 1 install, 0 updates, 0 removals

  • Installing nanobind (1.8.0)

Writing lock file

もし、poetry(Windows上)の環境構築も行いたい方はこちらを参照してください。

CMakeLists.txtの作成

Setting up a build system を参考にします。

まずは、下記のようなCMakeLists.txtを作成します。それぞれの説明は、リンク先等を参照してください。

cmake_minimum_required(VERSION 3.15)
project(nanobind-test LANGUAGES CXX) # Replace 'my_project' with the name of your project
find_package(Python 3.8 COMPONENTS Interpreter Development.Module REQUIRED)

if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
    set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
    set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()

# Detect the installed nanobind package and import it into CMake
execute_process(
    COMMAND "${Python_EXECUTABLE}" -m nanobind --cmake_dir
    OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE NB_DIR)
list(APPEND CMAKE_PREFIX_PATH "${NB_DIR}")
find_package(nanobind CONFIG REQUIRED)

nanobind_add_module(my_ext my_ext.cpp)

ビルドしてPythonから実行してみる

Creating your first extension を参考にします。

下記のようなmy_ext.cppを作成します。

#include <nanobind/nanobind.h>

int add(int a, int b) { return a + b; }

NB_MODULE(my_ext, m) {
    m.def("add", &add);
}

この時点でのディレクトリ構成は下記です。poetryで管理している方は他にもファイルがあるかもしれないですが、最低限はこちらのようになっていればOKです。

nanobind-test
|   CMakeLists.txt
|   my_ext.cpp
|
+---.venv
|   +---Lib
|   |   \---site-packages
|   |       +---nanobind
|   |       .
|   |
|   \---Scripts

では、buildしてみましょう。下記のような出力が出ればOKです。

> cmake -G "Visual Studio 17 2022" -S="." -B="./build" -DPython_EXECUTABLE="./venv/Scripts/python.exe"
-- The CXX compiler identification is MSVC 19.38.33130.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Tools/MSVC/14.38.33130/bin/Hostx64/x64/cl.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found Python: <path-to-project>/nanobind-test/.venv/Scripts/python.exe (found suitable version "3.10.11", minimum required is "3.8") found components: Interpreter Development.Module 
-- Configuring done (7.7s)
-- Generating done (0.1s)
-- Build files have been written to: <path-to-project>/nanobind-test/build

> cmake --build build --config Release
MSBuild version 17.8.3+195e7f5a3 for .NET Framework

  1>Checking Build System
  Building Custom Rule <path-to-project>/nanobind-test/CMakeLists.txt
  nb_internals.cpp
  nb_func.cpp
  nb_type.cpp
  nb_enum.cpp
  nb_ndarray.cpp
  nb_static_property.cpp
  common.cpp
  error.cpp
  trampoline.cpp
  implicit.cpp
  コードを生成中...
  nanobind-static.vcxproj -> <path-to-project>\nanobind-test\build\Release\nanobind-static.lib
  Building Custom Rule <path-to-project>/nanobind-test/CMakeLists.txt
  my_ext.cpp
     ライブラリ <path-to-project>/nanobind-test/build/Release/my_ext.lib とオブジェクト <path-to-project>/nanobind-test/build/Release/my_e
  xt.exp を作成中
  my_ext.vcxproj -> <path-to-project>\nanobind-test\build\Release\my_ext.cp310-win_amd64.pyd
  Building Custom Rule <path-to-project>/nanobind-test/CMakeLists.txt

ここで、仮想環境を使っている場合、下記の引数が必要です。

# ".venv\Scripts\python.exe"は各自のPythonへのパス
-DPython_EXECUTABLE=".venv\Scripts\python.exe"

build/Releaseディレクトリができているはずです。

buildディレクトリに移動し、下記のようにmy_ext.add関数が使えればOKです!

> cd build

> python
Python 3.10.11 (tags/v3.10.11:7d4cc5a, Apr  5 2023, 00:38:17) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import Release.my_ext as my_ext
>>> my_ext.add(1,2)
3

おわりに

今回は、公式ドキュメントに沿って、nanobindを動かすところまで記載しました。

今後は、実際に使っていく過程で便利な機能を書いていきたいと思っています。

Note(今後更新予定の内容やメモ)

GCCとMinGW

最初、MSVCではなく、GCC・MinGWで行おうとしていましたが、エラー(後述)でハマってしまい、MSVCにしました。

GCCのインストール

こちらに記載の通りの手順を踏むと、インストールできます。

Get Started with C++ and MinGW-w64 in Visual Studio Code
Configuring the C++ extension in Visual Studio Code to target g++ and gdb on a MinGW-w64 installation

最終的にgcc 13.1.0をインストールできました。(2023/11/18時点)

> gcc --version

gcc (Rev6, Built by MSYS2 project) 13.1.0
Copyright (C) 2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

エラー内容

下記でcmakeまで行った後に、

cmake -G "MinGW Makefiles" -DCMAKE_C_COMPILER:FILEPATH=C:\msys64\ucrt64\bin\gcc.exe -DCMAKE_CXX_COMPILER:FILEPATH=C:\msys64\ucrt64\bin\g++.exe -S . -B .\build -DPython_EXECUTABLE=".venv\Scripts\python.exe"

buildコマンドを打つと、下記のようなエラーが発生する。

(nanobind-test-py3.10) <path-to-project>\nanobind-test>cmake --build build
[  7%] Building CXX object CMakeFiles/nanobind-static.dir/.venv/Lib/site-packages/nanobind/src/nb_internals.cpp.obj
In file included from <path-to-project>/nanobind-test/.venv/Lib/site-packages/nanobind/include/nanobind/nanobind.h:47,
                 from <path-to-project>\nanobind-test\.venv\Lib\site-packages\nanobind\src\nb_internals.cpp:10:
<path-to-project>/nanobind-test/.venv/Lib/site-packages/nanobind/include/nanobind/nb_error.h:30:17
 error: 'dllexport' implies default visibility, but 'class nanobind::python_error' has already been declared with a different visibility
   30 | class NB_EXPORT python_error : public std::exception {
      |                 ^~~~~~~~~~~~
<path-to-project>/nanobind-test/.venv/Lib/site-packages/nanobind/include/nanobind/nb_error.h:98:17
 error: 'dllexport' implies default visibility, but 'class nanobind::builtin_exception' has already been declared with a different visibility
   98 | class NB_EXPORT builtin_exception : public std::runtime_error {
      |                 ^~~~~~~~~~~~~~~~~
mingw32-make[2]: *** [CMakeFiles\nanobind-static.dir\build.make:76: CMakeFiles/nanobind-static.dir/.venv/Lib/site-packages/nanobind/src/nb_internals.cpp.obj] Error 1
mingw32-make[1]: *** [CMakeFiles\Makefile2:109: CMakeFiles/nanobind-static.dir/all] Error 2
mingw32-make: *** [Makefile:90: all] Error 2

make

最初、cmakeにbuildコマンドがあることを知らなかったのでmakeをインストールしていました。( make コマンドと cmake --build build コマンドの違いがよくわかってない)

make のインストール

こちらからインストーラーをダウンロードできます。

Make for Windows
make {whatisit}

手順は、こちらを参考にしました。

make のインストール(Windows 上)
make のインストール(Windows 上)

VSCode CMake ToolsでのConfigure時に仮想環境からPythonパスを取ってくれない問題

問題

CMake ToolsのConfigureを使うと、.venvからPythonを取ってきてくれない。
find_package(Python) でWindowsの環境変数に書いてあるPythonを拾ってきちゃう。

このとき、VSCodeのターミナルは poetry shell で仮想環境をアクティベートしている。

おそらく、VSCodeの拡張機能では、poetryの環境下だと認識できていない(仮想環境をアクティベートできていない)ためだと思われる。解決方法があれば、追記する。

VS Code でCMakeLists.txtの保存時に自動でConfigureしないようにする設定。

  "cmake.configureOnEdit": false

解決のためにこれまで見たCMakeの参考記事など

コメント

タイトルとURLをコピーしました