こんにちは。RockinWoolです。
今日はC++とpythonの連携をするにあたって少し躓いた部分があったので紹介していきたいと思います。未だによくわかっていないバグもあったので、その辺で悩んでいる人たちへの一助になれれば幸いです。それでは早速見ていきましょう。

CMakeLists.txtの書き方

  1. cmake_minimim_requiredで最低限必要なcmakeのバージョンを指定してあげましょう
  2. projectの名前とバージョンをテキトーに定義しましょう
    この次からがpybindの特殊な設定になります
  3. find_package(pybind11 REQUIRED)でpybind11を探します
  4. find_package(Python REQUIRED)でPythonも探しておきます
  5. include_directories(/home/[userid]/anaconda3/include/(pybind11))でpybindをインクルードできるようにします。ただし。今回はここに関連したエラーが発生するので要確認
  6. link_directories(/home/[userid]/anaconda3/lib)でライブラリがリンクできるようにする
  7. あとは自分が作ったプログラムをビルドする部分です
    ここで注意するのはtarget_link_librariesでPUBLICを追記しておくことです。これはpybind11の書き方が内部でこうなっているらしく、書き方を統一しておく必要があります
    pybind11_add_module(main Main.cpp)
    add_library(caHistory utils/caHistory.cpp)
    target_link_libraries(main PUBLIC caHistory)

CMake Error at CMakeLists.txtのエラー

CMake Error at CMakeLists.txt:19 (target_link_libraries):
  The keyword signature for target_link_libraries has already been used with
  the target "cellauto".  All uses of target_link_libraries with a target
  must be either all-keyword or all-plain.

このエラーはtarget_link_librariesにPUBLICを入れていないと発生するエラーです。target_link_librariesの書き方には間にPUBLICを挟む書き方とそうでない書き方があり、pybindではPUBLICを挟んだ書き方をしているので統一してほしいというメッセージらしいです(ChatGPTより)。

fatal error: pybind11/pybind11.h: そのようなファイルやディレクトリはありません

CmakeLists.txtにちゃんと書いているにも関わらずpybind11が見つからないというエラー。実はこのエラーはadd_libraryとtarget_link_librariesが無い普通のc++ファイルをビルドした場合には発生しないエラーです。原因は不明ですが、main.cppの最初に#include <pybind11/pybind11.h>を書けば大丈夫で、クラスを定義しているヘッダファイル(例えばutil.hのように名前をつけていた)に#include <pybind11/pybind11.h>を書くとバグることがわかりました。もしかしたらライブラリにするcppファイルとmain.cppのフォルダ階層が異なるとうまく下位プログラムからpybind11を呼び出せない感じなのかもしれません。とにかくmain.cppに書きましょう。

TypeError: build.{library}.{class}: No constructor defined!

上記2つのエラーを乗り越えて無事にビルドが完了しても、pythonからうまく呼び出せるかは別問題です。そして、pythonから呼び出す際にはコンストラクタの実装が必要不可欠のようです。なので、コンストラクタを定義してあげましょう。さらにコンストラクタを登録する必要もあります。main.cppにコンストラクタを登録する方法は下記を参考に。

PYBIND11_MODULE(cellauto, m)
{
    py::class_<CA>(m, "CA")
        .def(py::init<>()) // コンストラクタの登録
        .def("caHistory", &CA::caHistory); //任意のクラスに登録された関数
}

まとめ

書き出してみるとちゃんと解決策のあるエラーだったのですが、C++はこういう仕様が隠れていて調べないとわからないみたいなエラーが多くて難しいですね。その点PYthonはかんたんだなと改めて感じます。それではここまで見てくださってありがとうございました。次回もお楽しみに。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です