pybind11ことはじめ

pybind11ことはじめ

目次

1 概要

  • C++11をPythonで利用しやすくするツールの一種
    • ヘッダーファイルのみで構成されている
    • DlibのPythonとの連携で使われていて調べた

2 関連文書

3 環境構築(Dockerを利用して)

  • 色々なOS(Windows,Mac,Linux)で、同じ操作で出来るように、Dockerを利用して環境を作る
  • Docker無しで、必要なツールをインストールして直接やってもOK(その場合この章はスキップ)
    • 必要なツール
      • C++のコンパイラ
      • CMake
      • GNU Make
      • Python とヘッダーファイル、ライブラリファイル
      • Python のライブラリ
        • pip
        • pybind11
    • あった方が良いもの
      • git
      • Python のライブラリ
        • ipython

3.1 以下の操作を行っている動画


3.2 環境構築(Dockerを利用して)の手順

3.2.1 事前準備

  • OSに依存せずに同じ環境作れるようにDockerを利用してこの動画シリーズやっていきます。
  • まずDockerをインストールしてください。
    • 私はUbuntu20.04の環境で行って行きます。DockerはWindowsやMacでも使えるので、他のOSでもDockerを入れれば同じ手順で出来ます。
  • Docker等でUbuntuの環境を用意
    • Python,Python-dev,c++コンパイラー,cmake,git等必要なパッケージインストール
  • 以下のコマンドで、共有用のディレクトリ作成し、user idを1000にしておく
sudo mkdir -p /work/pybind11
sudo chown 1000.1000 /work/pybind11

3.2.2 DockerのUbuntu20.04を利用して毎回必要なパッケージを入れる場合

  • ubuntu20.04を起動する
    • Docker内の/homeを/work/pybind11と共有
docker run -it --rm -v /work/pybind11:/home/ ubuntu:20.04
  1. Docker内で、必要なパッケージのインストール
    apt update
    apt upgrade
    apt -y install python3-dev python3-pip vim git g++ clang cmake make w3m less python3-ipython ipython3 nkf less diffutils patch sudo zlib1g-dev unzip locales 
    locale-gen ja_JP.UTF-8
    
    • pybind11パッケージのインストール
    pip3 install pybind11
    

3.2.3 pybind11を利用するのに必要なパッケージを入れたDockerイメージを作成する場合

  1. Dockerfileの準備
    • 以下の内容でDockerfileを作成
    FROM ubuntu:20.04
    MAINTAINER NM Max
    ENV user_n=user
    ENV user_id=1000
    #ENV DEBIAN_FRONTEND=noninteractive
    RUN apt -y update \
        && apt -y upgrade \
        && echo "6\n79\n" | apt -y install tzdata
    RUN apt -y install python3-dev python3-pip vim git g++ clang cmake make w3m less python3-ipython ipython3 nkf less diffutils patch sudo zlib1g-dev unzip locales \
        && locale-gen ja_JP.UTF-8 \
        && pip3 install pybind11
    ENV LC_ALL ja_JP.UTF-8
    ENV LANG ja_JP.UTF-8
    ENV LANGUAGE LANGUAGE=ja_JP:ja
    RUN echo 'LANG="ja_JP.UTF-8"' >> /etc/default/locale
    RUN echo "${user_n} ALL=NOPASSWD: ALL" >> /etc/sudoers
    WORKDIR /work
    RUN echo "\n\n\n\n\n\n\n" | adduser --uid ${user_id} --disabled-password ${user_n}
    RUN echo "user ALL=NOPASSWD: ALL" >> /etc/sudoers && chown user.user /work
    RUN mkdir -p /home/${user_n}/C && chown  ${user_n}.${user_n} /home/${user_n}/C
    ENTRYPOINT sudo su - ${user_n}
    
    • 以下のコマンドでイメージ作成
    docker build -t mypybind11 .
    
    • 作成したDockerイメージの起動は以下のコマンドで
    docker run -it --rm -v /work/pybind11:/home/user/C mypybind11
    

3.3 この章のまとめ

  • どのOSでも共通で利用できる環境をDockerで作成
  • Dockerの環境の準備が面倒なら、必要なツールをインストールして直接やってもよい

4 本家の文書のFirst stepsをやってみる

4.1 以下の操作を行っている動画


4.2 本家の文書のFirst stepsをやる手順

4.2.1 事前準備

  • OSに依存せずに同じ環境作れるようにDockerを利用してこの動画シリーズやっていきます。
  • まずDockerをインストールしてください。
    • 私はUbuntu20.04の環境で行って行きます。DockerはWindowsやMacでも使えるので、他のOSでもDockerを入れれば同じ手順で出来ます。
  • Docker等でUbuntuの環境を用意
    • Python,Python-dev,c++コンパイラー,cmake,git等必要なパッケージインストール
  1. 前の章で作成したmypybind11イメージを利用する場合
    • 前の章で作成した専用Dockerイメージmypybind11を起動
      • /work/pybind11 を Docker内の/homeと共通にしてます。
    docker run -it --rm -v /work/pybind11:/home/user/C mypybind11
    
    • 起動したDocker環境内で以下を実行
      • ubuntu20.04の場合は cd /home/user/C ではなく cd /home で
    cd /home/user/C
    mkdir test001
    cd test001/
    pwd
    
    • /home/user/C/test001 と表示され、現在の作業しているディレクトリを確認できます。
  2. 前の章で作成したmypybind11イメージを利用せずにUbuntu20.04を利用する場合
    • この場合、必要なものが入ってないので、Dockerイメージ起動あとに、必要なものを入れる必要があります。
    docker run -it --rm -v /work/pybind11:/home Ubuntu20.04
    
    • 以下を実行して必要なパッケージを入れる
    apt update
    apt upgrade
    apt install python3-dev python3-pip vim git g++ clang cmake make w3m less python3-ipython ipython3
    pip3 install pybind11
    
    • 起動したDocker環境内で以下を実行
      • ubuntu20.04の場合は cd /home/user/C ではなく cd /home で
    cd /home/
    mkdir test001
    cd test001/
    pwd
    
    • /home/test001 と表示され、現在の作業しているディレクトリを確認できます。

4.2.2 example.cppの準備

4.2.3 コンパイル

c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)

4.2.4 動作確認

  • 対話環境で動作確認した方がやりやすいので、IPythonを起動する
ipython3
  • 作成したモジュールの読み込み
import example                                                                                                                                
  • 1+2をやってみる
example.add(1,2)                                                                                                                              
  • 1+2で3が表示されます
  • 次に5+6をやってみる。
example.add(5,6)   
  • 5+6で11が表示されます

4.3 この章のまとめ

  • 本家文書のFirst stepsをやってみた
  • 使い方の基本の確認
  • C++で作成した関数をPythonで利用する手順の理解

5 CMakeで前章の内容をやってみる

5.1 以下の操作を行っている動画


5.2 cmakeで前章の内容をやってみる手順

5.2.1 事前準備

  • 必要なソフトを入れる
  • 前の章のexample.cppを入れておく
  • example.cppのあるディレクトリに移動
  1. 以下のコマンドでpybind11の最新バージョンをダウンロードして利用しても良い
    git clone https://github.com/pybind/pybind11
    
    • 以下のコマンドでバックアップ取っておいても良いかも
    tar cvzf pybind11_`date +%Y%m%d_%H%M`.tgz pybind11/
    

5.2.2 CMakeLists.txt の準備

cmake_minimum_required(VERSION 3.4...3.18)
project(example LANGUAGES CXX)

add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)

5.2.3 コンパイル

mkdir build
cd build
cmake ..
make 
  • 前の章と同じ手順で動作確認すべき

5.3 この章のまとめ

  • 前章の内容をcmakeを利用してやってみた
  • コンパイルがちょい楽に

6 classを利用その1

6.1 以下の操作を行っている動画


6.2 classを利用その1の手順

  • この動画で以前作成したDockerイメージを起動
  • 作業用ディレクトリにてCMakeLists.txtとexample.cppの2つを用意

6.2.1 以前作成したDockerイメージの起動

docker run -it --rm -v /work/pybind11:/home/user/C mypybind11

6.2.2 作業用のディレクトリの作成と移動

cd /home/user/C
mkdir test002
cd test002/
pwd

6.2.3 CMakeLists.txt の作成

cmake_minimum_required(VERSION 3.4...3.18)
project(example LANGUAGES CXX)

add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)

6.2.4 example.cppの作成

  • 前の章で利用したものに簡単なクラスTest01を追加
  • Class Test01をPython側で利用出来るようにコード追加
    • def_readwrite でpublicのメンバ変数を参照してPythonから使えるようにした
    • コンストラクタと、helloメンバ関数を参照してPythonから使えるようにした
#include <pybind11/pybind11.h>
#include <string>
namespace py = pybind11;

int add(int i, int j) {
    return i + j;
}

class Test01 {
        public:
                Test01(const std::string &s) {
                        name=s;
                }
                std::string name;
                std::string hello() {
                        return "Hello "+name+"!";
                }
};

// https://pybind11.readthedocs.io/en/stable/classes.html#instance-and-static-fields
// https://pybind11.readthedocs.io/en/stable/classes.html#binding-lambda-functions
PYBIND11_MODULE(example, m) {
        m.doc() = "pybind11 example plugin"; // optional module docstring

        m.def("add", &add, "A function which adds two numbers");
        py::class_<Test01>(m, "Test01")
                .def(py::init<const std::string &>())
                .def_readwrite("name", &Test01::name)
                .def("hello", &Test01::hello);
}

6.2.5 pybind11の最新をgitでゲット

git clone https://github.com/pybind/pybind11

6.2.6 コンパイル

mkdir build
cd build
cmake ..
make 

6.2.7 動作確認

  • ipythonを起動して確認すると対話形式なので色々試しやすい
import example
m=example.Test01("Tom")
m.name
m.hello()
  • 次の章でオブジェクトを文字列化するところをカスタマイズするので、一度表示してみる。
m
  • 内部の情報とかは現状見れない。次の章でここらの表現をカスタマイズします。
  • 次の章で、ダイナミックに属性を追加出来るようにするので、現在出来ないことを確認
m.age=32                                                                                                                                      
  • AttributeError: ‘example.Test01’ object has no attribute ‘age’ が表示される

6.3 この章のまとめ

  • classをやってみた。

7 classを利用その2

7.1 以下の操作を行っている動画


7.2 classを利用その2の手順

  • この動画で以前作成したDockerイメージを起動
  • 作業用ディレクトリにてCMakeLists.txtとexample.cppの2つを用意

7.2.1 以前作成したDockerイメージの起動

docker run -it --rm -v /work/pybind11:/home/user/C mypybind11

7.2.2 作業用のディレクトリの作成と移動

cd /home/user/C
mkdir test003
cd test003/
pwd

7.2.3 CMakeLists.txt の作成

cmake_minimum_required(VERSION 3.4...3.18)
project(example LANGUAGES CXX)

add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)

7.2.4 example.cppの作成

  • 前の章で利用したものに多少修正
    • Class Test01のpybind11用記述部分に2箇所追加
      • py::dynamic_attr()追加 これにより 動的に属性追加可能に。 dict でそれらの情報出てくる。
        • .def(“repr“, …. 部分追加 これにより、クラスオブジェクトの表示をカスタマイズ
#include <pybind11/pybind11.h>
#include <string>
namespace py = pybind11;

int add(int i, int j) {
    return i + j;
}

class Test01 {
        public:
                Test01(const std::string &s) {
                        name=s;
                }
                std::string name;
                std::string hello() {
                        return "Hello "+name+"!";
                }
};

PYBIND11_MODULE(example, m) {
        m.doc() = "pybind11 example plugin"; // optional module docstring

        m.def("add", &add, "A function which adds two numbers");
        py::class_<Test01>(m, "Test01", py::dynamic_attr())
                .def(py::init<const std::string &>())
                .def_readwrite("name", &Test01::name)
                .def("hello", &Test01::hello)
                .def("__repr__",
                        [](const Test01 &a) {
                            return "<example.Test01 named '" + a.name + "'>";
                        }
                );
}

7.2.5 pybind11の最新をgitでゲット

git clone https://github.com/pybind/pybind11

7.2.6 コンパイル

mkdir build
cd build
cmake ..
make 

7.2.7 動作確認

  • ipythonを起動して確認すると対話形式なので色々試しやすい
import example
m=example.Test01("Tom")
m.name
m.hello()
  • 次の章でオブジェクトを文字列化するところをカスタマイズするので、一度表示してみる。
m
  • 表示がカスタマイズされて、nameの情報が表示されるようになった
  • 動的に属性を追加出来るようになっているので、試す。
m.age=32                                                                                                                                      
m.age  
print(m.__dict__)
  • 内部情報が表示されるようになった。

7.3 さらなる使い方

7.4 この章のまとめ

  • 前章のClassに動的に属性を追加出来るようにした。
  • 前章のClassを文字列化した時の表現のカスタマイズを行った。

8 コンテナを利用(std::vector) 1

8.1 以下の操作を行っている動画


8.2 コンテナを利用(std::vector) 1 の手順

  • この動画で以前作成したDockerイメージを起動
  • 作業用ディレクトリにてCMakeLists.txtとexample.cppの2つを用意

8.2.1 以前作成したDockerイメージの起動

docker run -it --rm -v /work/pybind11:/home/user/C mypybind11

8.2.2 作業用のディレクトリの作成と移動

cd /home/user/C
mkdir test004
cd test004/
pwd

8.2.3 CMakeLists.txt の作成

cmake_minimum_required(VERSION 3.4...3.18)
project(example LANGUAGES CXX)

add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)

8.2.4 example.cppの作成

  • pybind11/stl.h をインクルード
  • C++ で2つの関数を定義
    • range関数,最初、最後、差を与えると、等差数列をかえす関数
      • 無限ループ回避の処理をいれたら、ちょい不細工に
    • concatv 2つの整数(int)の数列を結合してかえす関数
  • Pythonに渡す関数の記述
    • 2つの関数の記述
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <vector>
namespace py = pybind11;

std::vector<int> range(int st, int end, int diff) {
  std::vector<int> ans;
  bool flag=(end-st)*diff>=0;
  if(flag && diff!=0) {
    if(end>=st) {
      for(int i=st;i<=end;i+=diff) {
        ans.push_back(i);
      }
    } else {
      for(int i=st;i>=end;i+=diff) {
        ans.push_back(i);
      }
    }
  } else {
    ans.push_back(st);
  }
  return ans;
}       

std::vector<int> concatv(const std::vector<int> &a, const std::vector<int> &b) {
  std::vector<int> ans;
  for(int i=0;i<a.size();++i) {
    ans.push_back(a[i]);
  }
  for(int i=0;i<b.size();++i) {
    ans.push_back(b[i]);
  }
  return ans;
}       

PYBIND11_MODULE(example, m) {
  m.doc() = "pybind11 example plugin"; // optional module docstring

  m.def("range", &range, "A function which make a arithmetic progression");
  m.def("concatv", &concatv, "A function which concatenate two int vector");
}

8.2.5 pybind11の最新をgitでゲット

git clone https://github.com/pybind/pybind11

8.2.6 コンパイル

mkdir build
cd build
cmake ..
make 

8.2.7 動作確認

  • ipythonを起動して確認すると対話形式なので色々試しやすい
import example
example.range(1,10,1)
example.range(1,10,2)
example.range(10,1,-1)
example.range(1,10,-1)
example.range(1,10,0)
example.concatv([5,6],[1,2,3])
example.concatv([1,2,3],[4,5])

8.3 この章のまとめ

  • std::vectorを使ったC++関数をPython側から使えるようにしてみた。

9 コンテナを利用(std::vector) 2 (Making opaque typesの1 意図したように動かない例)

9.1 以下の操作を行っている動画


9.2 コンテナを利用(std::vector) 2 (Making opaque typesの1 意図したように動かない例) の手順

9.2.1 以前作成したDockerイメージの起動

docker run -it --rm -v /work/pybind11:/home/user/C mypybind11

9.2.2 作業用のディレクトリの作成と移動

cd /home/user/C
mkdir test005
cd test005/
pwd

9.2.3 CMakeLists.txt の作成

cmake_minimum_required(VERSION 3.4...3.18)
project(example LANGUAGES CXX)

add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)

9.2.4 example.cppの作成

 - このままコピペじゃ動かないので、不足分を追加して実際に動かしてみる  - この例は意図した動作になっていない。自分でも同じことする時は気をつけるべき

  • 意図する動作にする手順は次の章で
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <vector>

namespace py = pybind11;

void append_1(std::vector<int> &v) {
  v.push_back(1);
}

class MyClass {
  public:
    std::vector<int> contents;
};

/* ... binding code ... */


PYBIND11_MODULE(example, m) {
  m.doc() = "pybind11 example plugin"; // optional module docstring

  m.def("append_1", &append_1);
  py::class_<MyClass>(m, "MyClass")
      .def(py::init<>())
      .def_readwrite("contents", &MyClass::contents);
}

9.2.5 pybind11の最新をgitでゲット

git clone https://github.com/pybind/pybind11

9.2.6 コンパイル

mkdir build
cd build
cmake ..
make 

9.2.7 動作確認

  • ipythonを起動して確認すると対話形式なので色々試しやすい
import example
v=[1,2,3]
example.append_1(v)
v
  • [1,2,3,1]ではなく[1,2,3]がかえってくる
  • クラスの方もやってみる
m = example.MyClass()
m.contents = [5, 6]
m.contents
m.contents.append(7)
m.contents
  • これも[5,6,7]ではなく[5,6]がかえってくる

9.3 この章のまとめ

10 コンテナを利用(std::vector) 3 (Making opaque typesの2 意図したように動くようにOPAQUEを使う)

10.1 以下の操作を行っている動画


10.2 コンテナを利用(std::vector) 3 (Making opaque typesの2 意図したように動くようにOPAQUEを使う)手順

  • 手順は前の章と同じになるので、前の章と異る部分、example.cppのみここに記載します。

10.2.1 example.cppの作成

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <vector>
#include <string>

namespace py = pybind11;

void append_1(std::vector<int> &v) {
  v.push_back(1);
}

class MyClass {
  public:
    std::vector<int> contents;
};

/* ... binding code ... */

PYBIND11_MAKE_OPAQUE(std::vector<int>);

PYBIND11_MODULE(example, m) {
  m.doc() = "pybind11 example plugin"; // optional module docstring

  py::class_<std::vector<int>>(m, "IntVector")
    .def(py::init<>())
    .def("clear", &std::vector<int>::clear)
    .def("pop_back", &std::vector<int>::pop_back)
    .def("push_back", (void (std::vector<int>::*)(const int &)) &std::vector<int>::push_back)
    .def("__len__", [](const std::vector<int> &v) { return v.size(); })
    .def("__iter__", [](std::vector<int> &v) {
       return py::make_iterator(v.begin(), v.end());
    }, py::keep_alive<0, 1>()); /* Keep vector alive while iterator is used */

  m.def("print_opaque_list", [](const std::vector<int> &l) {
        std::string ret = "Opaque list: [";
        bool first = true;
        for (auto entry : l) {
            if (!first)
                ret += ", ";
            ret += std::to_string(entry);
            first = false;
        }
        return ret + "]";
    });


  m.def("append_1", &append_1);
  py::class_<MyClass>(m, "MyClass")
      .def(py::init<>())
      .def_readwrite("contents", &MyClass::contents);
}

10.2.2 動作確認

import example
m=example.MyClass()
example.print_opaque_list(m.contents)
m.contents.push_back(1)
m.contents.push_back(2)
example.print_opaque_list(m.contents)
example.append_1(m.contents)
example.print_opaque_list(m.contents)
example.append_1(m.contents)
example.print_opaque_list(m.contents)

10.3 この章のまとめ

11 コンテナを利用(std::vector) 4 (Making opaque typesの3 意図したように動くようにOPAQUEと、Binding STL containersを使う)

11.1 以下の操作を行っている動画


11.2 コンテナを利用(std::vector) 4 (Making opaque typesの3 意図したように動くようにOPAQUEと、Binding STL containersを使う) 手順

  • 手順は以前の章と同じになるので、前の章と異る部分、example.cppのみここに記載します。

11.2.1 example.cppの作成

 - このままコピペじゃ動かないので、不足分を追加して実際に動かしてみる  - この例は意図した動作になっていない。自分でも同じことする時は気をつけるべき

  • 意図する動作にする手順は次の章で
  • ../pybind11/tests/test_opaque_types.cpp を参考に
    • push_backを追加(std::vector<int>用に修正)
    • print_opaque_list(std::vector<int>用に修正)
#include <pybind11/pybind11.h>
#include <pybind11/stl_bind.h>
#include <vector>
#include <string>

namespace py = pybind11;

void append_1(std::vector<int> &v) {
  v.push_back(1);
}

class MyClass {
  public:
    std::vector<int> contents;
};

/* ... binding code ... */

PYBIND11_MAKE_OPAQUE(std::vector<int>);

PYBIND11_MODULE(example, m) {
  m.doc() = "pybind11 example plugin"; // optional module docstring

  py::bind_vector<std::vector<int>>(m, "VectorInt");

  m.def("append_1", &append_1);
  py::class_<MyClass>(m, "MyClass")
      .def(py::init<>())
      .def_readwrite("contents", &MyClass::contents);
}

11.2.2 動作確認

import example
m=example.MyClass()
m.contents
m.contents=example.VectorInt([1,2,3])
example.append_1(m.contents)
m.contents
m.contents.append(5)
m.contents

11.3 この章のまとめ

12 引数に名前をつける

12.1 以下の操作を行っている動画


12.2 引数に名前をつける手順

  • 手順は以前の章と同じになるので、前の章と異る部分、example.cppのみここに記載します。

12.2.1 example.cppの作成

#include <pybind11/pybind11.h>
namespace py = pybind11;

int add(int i, int j) {
    return i + j;
}

PYBIND11_MODULE(example, m) {
    m.doc() = "pybind11 example plugin"; // optional module docstring

 // m.def("add", &add, "A function which adds two numbers"); // org
    m.def("add", &add, "A function which adds two numbers", py::arg("i"), py::arg("j"));
}

12.2.2 動作確認

import example
example.add(i=1,j=2)

12.3 この章のまとめ

13 引数にデフォルト値を設定

13.1 以下の操作を行っている動画


13.2 引数にデフォルト値を設定する手順

  • 手順は以前の章と同じになるので、前の章と異る部分、example.cppのみここに記載します。

13.2.1 example.cppの作成

#include <pybind11/pybind11.h>
namespace py = pybind11;

int add(int i, int j) {
    return i + j;
}

PYBIND11_MODULE(example, m) {
    m.doc() = "pybind11 example plugin"; // optional module docstring

 // m.def("add", &add, "A function which adds two numbers"); // org
 // m.def("add", &add, "A function which adds two numbers", py::arg("i"), py::arg("j")); // 前の章
    m.def("add", &add, "A function which adds two numbers", py::arg("i")=1, py::arg("j")=2);
}

13.2.2 動作確認

import example
example.add(i=2)
example.add(j=3)
example.add()

13.3 この章のまとめ

14 変数のエクスポート

14.1 以下の操作を行っている動画


14.2 変数のエクスポート 手順

  • 手順は以前の章と同じになるので、前の章と異る部分、example.cppのみここに記載します。

14.2.1 example.cppの作成

#include <pybind11/pybind11.h>
namespace py = pybind11;

PYBIND11_MODULE(example, m) {
    m.attr("the_answer") = 42;
    py::object world = py::cast("World");
    m.attr("what") = world;
}

14.2.2 動作確認

import example
example.the_answer
example.the_answer=53
example.the_answer
example.what
example.what="hoho"
example.what

14.3 この章のまとめ

15 オーバーロードされたメソッド

15.1 以下の操作を行っている動画


15.2 オーバーロードされたメソッドをPythonで利用する手順

  • C++14以前の方法と、C++14以降とでやり方2つある
  • C++14以降の方が記述が楽なので、こっちだけ動画で説明します。(もう一つの方法は Overloaded methods https://pybind11.readthedocs.io/en/stable/classes.html#overloaded-methodsをご覧ください)
  • pybind11では自動で、それらのメソッドを自動で選択してくれない、なので、ひとつひとつ引数を記述して記述していく
  • Dockerイメージの起動からコンパイルまでの手順は以前の動画 https://www.youtube.com/embed/fBW69-x4n6U を参考にやってください。

15.2.1 C++ソースファイルの作成

#include <pybind11/pybind11.h>
namespace py = pybind11;

struct Widget {
  int foo(int x, float y) {
    return x+y;
  }
  int foo(int x, float y) const {
    return x-y;
  }
};

PYBIND11_MODULE(example, m) {
    m.doc() = "pybind11 example plugin"; // optional module docstring
    py::class_<Widget>(m, "Widget")
       .def(py::init<>())
       .def("foo_mutable", py::overload_cast<int, float>(&Widget::foo))
       .def("foo_const",   py::overload_cast<int, float>(&Widget::foo, py::const_));
}

15.2.2 CMakeLists.txt の作成

cmake_minimum_required(VERSION 3.4...3.18)

set(CMAKE_CXX_STANDARD 14)          # C++14以上に設定する
set(CMAKE_CXX_STANDARD_REQUIRED ON) # 設定のC++のバージョン条件を満たせないならエラーにする
set(CMAKE_CXX_EXTENSIONS OFF)       # 互換性を高める

project(example LANGUAGES CXX)

add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)

15.2.3 pybind11の最新をgitでゲット

git clone https://github.com/pybind/pybind11

15.2.4 コンパイル

  • 以前の章と同じコマンド
mkdir build
cd build
cmake ..
make 

15.2.5 動作確認

  • ipythonを起動して確認すると対話形式なので色々試しやすい
import example
w=example.Widget()
w.foo_mutable(1,2)
w.foo_const(1,2)

15.3 この章のまとめ

  • オーバーロードされたメソッドの取扱方法の1つを行なった。

16 モジュール名に注意

  • CMakeLists.txt内のモジュール名とc++ソースのモジュール名が異ると、コンパイルは可能なのですが、モジュール読み込み時にエラーが発生
  • Dockerイメージの起動からコンパイルまでの手順は以前の動画 https://www.youtube.com/embed/fBW69-x4n6U を参考にやってください。

16.1 以下の操作を行っている動画


16.2 モジュール名に注意 の確認手順

  • 前のソースのCMakeLists.txtの pybind11_add_module(example example.cpp) を pybind11_add_module(widget example.cpp) とか、別名にしてみる
  • コンパイルしなおして、モジュール読み込むと以下のエラーが発生
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
<ipython-input-1-64ca027457b3> in <module>
----> 1 import widget

ImportError: dynamic module does not define module export function (PyInit_widget)
  • ということで、 CMakeLists.txt内のモジュール名と、C++ソースのモジュール名同じにする必要があります。(こないだこれでハマり、時間ロスしました)

16.3 この章のまとめ

  • CMakeLists.txt のモジュール名と、C++ソースで記述したモジュール名は同じにしましょう。そうしないとエラー発生。

17 今後

  • 今後も文書追加していきます。

18 この文書のチェンジログ

  • 2021/05/08 初版
  • 2021/05/10 classを利用その1 の章, classを利用その2 の章追加
  • 2021/05/10 Dockerイメージの起動のコマンドに誤りがあったので修正
  • 2021/05/11 コンテナを利用(std::vector) 1 の章追加
  • 2021/05/12 コンテナを利用(std::vector) 2 (Making opaque typesの1 意図したように動かない例) の章、コンテナを利用(std::vector) 3 (Making opaque typesの2 意図したように動くようにOPAQUEを使う) の章、 * コンテナを利用(std::vector) 4 (Making opaque typesの3 意図したように動くようにOPAQUEと、Binding STL containersを使う) の章追加
  • 2021/05/13 引数に名前をつける の章、 引数にデフォルト値を設定 の章、 変数のエクスポート の章追加
  • 2021/05/21 オーバーロードされたメソッド の章追加, モジュール名に注意 の章追加
  • 2021/05/24 BlogへのアップロードをMarkDownに変換して登録するように変更

著者: NM Max

Created: 2021-05-24 月 23:42

Validate

コメントを残す

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