18
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

pybind11入門(1)

Open3DやDlibのソースコードを読んでいるとpybind11という何やらすてきなものを使ってPythonのライブラリを作っているので試してみた。

準備

cmakeを使用します。pybind11はヘッダーだけのライブラリで、github (https://github.com/pybind/pybind11/releases) などからダウンロードして以下のようなディレクトリ配置にします。

project top
|- CMakeLists.txt
|- pybind11/ 
|- mymodule.cpp

ソースコード

mymodule.cpp には以下のように書きます。

#include <pybind11/pybind11.h>

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

PYBIND11_MODULE(mymodule, m)
{
    m.doc() = "my test module";
    m.def("add", &add, "add two numbers");
}

PYBIND11_MODULE というマクロを使用してPythonモジュールを作成できます。引数の1つめのmymoduleはモジュールの名前で最終的に作成するライブラリのファイル名と揃える必要があります。 (mymodule.cpython-37m-x86_64-linux-gnu.so のような名前になる場合は mymodule)

2つ目の引数 m はマクロ内でのみ使用するもので、その後のように m.def を使用して関数を登録します。

これをビルドする際には次のような CMakeLists.txt を作成します。

cmake_minimum_required(VERSION 3.2)
project(pybind_test VERSION 0.1.0)

add_subdirectory(pybind11)
pybind11_add_module(mymodule mymodule.cpp)

このままビルドするとデフォルトのPythonが使用されます。vritualenvやcondaで作った特定のバージョンのPython環境に対してビルドしたい場合は事前にその環境をactivateするか、 cmake -DPYTHON_EXECUTABLE=path/to/python .. のように指定します。 LinuxでPython3.7に対してビルドするとmymodule.cpython-37m-x86_64-linux-gnu.so というファイルができます。これをPYTHONPATHが通っている場所(例えばカレントディレクトリ)におけばimportできます。

import mymodule
mymodule.add(1, 10)
>> 11

ソースファイルの分割

プロジェクトが大きくなったり、もともとあるC/C++のコードを利用したいというときに全てのコードを mymodule.cpp に書くわけには行きません。ソースコードを複数に分割する場合には次のようにします。

project top
|- CMakeLists.txt
|- pybind11/ 
|- mymodule.cpp
|- lib.cpp
|- lib.hpp
lib.hpp
int add(int a, int b);
lib.cpp
#include "lib.hpp"

int add(int a, int b)
{
    return a + b;
}
mymodule.cpp
#include <pybind11/pybind11.h>
#include "lib.hpp"

PYBIND11_MODULE(mymodule, m)
{
    m.doc() = "my test module";
    m.def("add", &add, "add two numbers");
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.2)
project(pybind_test VERSION 0.1.0)

set(CMAKE_POSITION_INDEPENDENT_CODE ON)

add_subdirectory(pybind11)

add_library(test lib.cpp)

pybind11_add_module(mymodule mymodule.cpp)
target_link_libraries(mymodule PRIVATE test)

ポイントはadd_libraryを使用してPythonと関係ないライブラリを作成したあと、target_link_librariesでpybind11で作ったmoduleとそれを結合します。もちろんpybind11_add_moduleで全てのソースファイルを指定しても良いのですが、こちらのほうが通常のC/C++用ライブラリとPython用ライブラリの両方ができるので何かと便利だと思います。

参考

公式doc: https://pybind11.readthedocs.io/en/stable/index.html

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
18
Help us understand the problem. What are the problem?