LoginSignup
2
2

More than 1 year has passed since last update.

M1 MACでpybind11を導入する

Posted at

目的

pybind11はc++のコードを簡単にpythonから呼び出せ非常に便利ですが、あまりリファレンスが多くないのと、実行環境によって導入方法が結構異なるので
m1 macでの導入方法をメモ。

pybind11

pybind11は、主に既存のC ++コードのPythonバインディングを作成するために、PythonでC++型を公開する軽量のヘッダー専用ライブラリです。
公式ドキュメント

cythonとかboost pythonとかあるけどpybind11が一番楽でオーバーヘッドも少ない印象。

実行環境

M1 MacBook Air

ProductName:	macOS
ProductVersion:	12.3.1
BuildVersion:	21E258

インストール

M1 macはまだまだcondaが使いづらいので今回はpipenvを使用します。
pipenvだとpythonのバージョンがらpipライブラリのバージョン、依存関係まで管理できます。
pipenvの情報はこちら

Macなのでbrewを使います

brew install pipenv

pipenvのパッケージを作業ディレクトリ直下に保管したいので以下のコマンドを実行

export PIPENV_VENV_IN_PROJECT=1

pythonのバージョンを指定します

pipenv --python 3.9.9

pipenvで仮想環境構築

pipenv install

これで作業ディレクトリに.venvディレクトリが作成され、中にパッケージが格納されます。
また、Pipfileというテキストファイルも作成され、ここにバージョンの情報が保存されます。

pybind11のインストール

pipenv install pybind11

この時点でPipfileは以下のようになっています

[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
pybind11 = "*"

[dev-packages]

[requires]
python_version = "3.9"

pybind11のinclude path

pybind11はheader-only library であるため、headerのincludeパスさえわかっていれば使用できます。
確認方法は

python3 -m pybind11 --includes

です。おそらくhomebrewは以下のパスもしくは.venvは以下のincludeのパスが表示されていると思います。

c++モジュール作成

何はともあれinstallが環境したらcppのコードを書きます。公式ドキュメントから簡単な和算の関数を作成します
ちなみにここでvscodeで作業する場合は.vscode/c_cpp_properties.json内に先ほどの
python3 -m pybind11 --includesの結果のパスを入れることでvscodeがpybind11を認識してくれます

example.cpp
#include <pybind11/pybind11.h>

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 that adds two numbers");
}

#include でpybind11を呼び出して、add関数を作成した後、

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

    m.def("add", &add, "A function that adds two numbers");
}

でpythonで呼び出せる形式を整えています。
ここでm.def("add", &add, "A function that adds two numbers");についてpython側で呼び出す際の引数名やdocsを定義しています。
c++側の準備は以上となります。

コンパイル & pythonから呼び出し

ここまでできたらあとはコンパイルしてpythonからimportできる形式のファおりに変換して、それをpythonからimportするだけです。
公式ドキュメントにMacOS用のコンパイルコマンドが乗っているのでそれをそのまま使用します。exampleのところは作成したcppファイル、作成するbuiltファイル名を好きにつけることができます。

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

そうするとexample.cppのあったディレクトリに新しいファイルが作成されています

example.cpython-39-darwin.so

.cpython-39-darwin.soといいうのはpythonがc/c++のビルドされたファイルを読み込むための拡張子でosによって変わったりします。今回のコマンドではpython3-config --extension-suffixで取得した拡張子をそのまま使用しているので問題ないです。

ビルドに管んする情報はここに色々記載があります。

作成した関数をpythonから呼び出してみます。

bash-3.2$ python
Python 3.9.9 (main, Nov 21 2021, 03:16:13) 
[Clang 13.0.0 (clang-1300.0.29.3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import example
>>> example.add(1, 2)
3

以上!c++のコードをpythonで使用することができました!

その他エラー

clang: error:

最初Linux用のbuildコマンドを使用したのでエラーが出てしまいました

# linux用のコマンド
c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)

clang: error: linker command failed with exit code 1 (use -v to see invocation)っていうg++でよくあるエラーが出てくるので要注意です。(このエラー調べてもまずpybind11には辿り着けません。)

miniforge3

M1Macでcondaを使用するかたはminiforge3から使用する方も多いかもしれません。私の環境ではminiforge3からconda createで仮想化環境を構築してpybind11を導入したところ、ビルドはできたんですが、pythonでimportはできませんでした。(import error)
原因はついにわかりませんでしたが、
.cpython-39-darwin.soを読み込む他のライブラリ(つまりc/c++の力を借りているpythonライブラリ)はM1 Macでよくエラーを見かけるのでまだM1が対応していないのかもしれないですね

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2