質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
バインド

バインドは、一定の方法で複数の事柄が関連付けられている状態を呼びます。また、そのような関連付けを実行する機能自体を指す事もあります。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

0回答

1733閲覧

pybind11等を使って静的ライブラリをバインドする方法

kamontia

総合スコア7

バインド

バインドは、一定の方法で複数の事柄が関連付けられている状態を呼びます。また、そのような関連付けを実行する機能自体を指す事もあります。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/06/18 16:14

編集2020/06/19 00:10

実現したいこと

事前にコンパイルされた静的ライブラリをpybind11を使ったラッパー関数を用意してPythonで呼び出したい。

言語間のバインディングについては知識が全くなく、以下のことが実現できるか教えて頂きたいです。

  • 手元にソースコードがないC++のコードをPybind11を使って共有ライブラリを作ることでPythonから呼び出せるか?

以下の状況を考え、静的ライブラリのIFを知っていることを条件にラッパー関数作成しました。

bash

1. 2├── lib 3│ ├── hello.cpp // ソースコードは提供されないと仮定 4│ ├── hello.o // 同上 5│ └── libhello.a // 静的ライブラリ 6└── wrapper 7 ├── wrapper.cpp // 今回作成したラッパー用の関数 8 └── wrapper.cpython-37m-x86_64-linux-gnu.so // pybind11でビルドした共有ライブラリ

該当のソースコード

hello.cpp: 提供されない想定

c++

1#include <iostream> 2#include <string> 3 4void hello(const std::string &name) { 5 std::cout << "Hello " << name << std::endl; 6}

wrapper/wrapper.cpp: 静的ライブラリの関数を呼び出すためのラッパー関数

c++

1#include <pybind11/pybind11.h> 2#include <string> 3extern void hello(const std::string &name); 4 5int wrap_hello() { 6 hello("MAIN"); 7 return 0; 8} 9 10namespace py = pybind11; 11PYBIND11_MODULE(hello_wrap, m) { 12 m.doc() = "Hello wrapper"; 13 m.def("wrap_hello", &wrap_hello, "Call hello method"); 14}

wrapper.cpython-37m-x86_64-linux-gnu.so: pybind11 を使って共有ライブラリを作成
※yymmtさんの指摘により共有ライブラリのPrefixをPYBIND11_MODULEの第一引数に合わせました

bash

1g++ -O3 -Wall -shared -std=c++11 -fPIC `python3 -m pybind11 --includes` wrapper.cpp -o hello_wrap`python3-config --extension-suffix`

発生している問題・エラーメッセージ

試しにPythonでモジュールをインポートすると静的ライブリで定義しているhelloが未定義だとエラーが出力されます。

bash

1$ python 2Python 3.7.3 (default, May 29 2019, 08:41:00) 3[GCC 7.4.0] on linux 4Type "help", "copyright", "credits" or "license" for more information. 5>>> import wrapper 6Traceback (most recent call last): 7 File "<stdin>", line 1, in <module> 8ImportError: /home/hogehoge/wrapper/wrapper.cpython-37m-x86_64-linux-gnu.so: undefined symbol: _Z5helloRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE 9>>>

bash

1$ nm -C wrapper.cpython-37m-x86_64-linux-gnu.so |grep -i hello -A 1 20000000000004e50 T PyInit_hello_wrap 3 U PyInstanceMethod_New 4-- 50000000000004dc0 T wrap_hello() 6 U hello(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) 7 U operator delete(void*)@@GLIBCXX_3.4

試したこと

リンクオプションにlibhello.aの指定を追加
※yymmtさんの指摘により共有ライブラリのPrefixをPYBIND11_MODULEの第一引数に合わせました

bash

1g++ -O3 -Wall -shared -std=c++11 -fPIC -L ../lib -lhello `python3 -m pybind11 --includes` wrapper.cpp -o hello_wrap`python3-config --extension-suffix`

補足情報(FW/ツールのバージョンなど)

Ubuntu 18.04
python 3.7.3
g++ 7.5.0

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

SHOMI

2020/06/18 16:59

libhello.aはリンクしなくていいんですか?
yymmt

2020/06/18 23:20

細かいことですが PYBIND11_MODULEの第一引数と共有ライブラリのprefixを一致させる必要があります(hello_wrap.cpython-37m-x86_64-linux-gnu.soが作られるようにしないとimport時に怒られます)。
kamontia

2020/06/19 00:12

SHOMIさん 「試したこと」に追記(記載漏れでした)していますが、libhello.aをリンク指定しています。相変わらずnmコマンドではシンボル未定義になっています。 yymmtさん ありがとうございます。認識していたつもりが間違えておりました。
yymmt

2020/06/19 23:17

こちらでもやって見ましたが、動いてしまいました・・・。libhello.aはC++ではなくてC言語ですか?そしたらマングリングの問題かも知れません。プロトタイプ宣言をextern "C" {}で囲うのはどうでしょう?
kamontia

2020/06/20 12:28

yymmtさん 実際に試して頂きありがとうございます。libhello.aはC++のコードです。「g++ -c hello.cpp; ar rv libhello.a hello.o」で静的ライブラリ作成しています。念の為、extern "C"で試しましたが、「undefined symbol: hello」となりました。もう少し調べます。
kamontia

2020/06/20 12:46

そもそも、静的ライブラリと共有ライブラリを混同してコンパイルということはできないのでしょうか?libhello.aを共有ライブラリとして「g++ -shared -fPIC -o libhello.so hello.cpp」としてlibhello.soとして作成すると、pyhon側でimportすることができました。
yymmt

2020/06/20 15:30

> そもそも、静的ライブラリと共有ライブラリを混同してコンパイルということはできないのでしょうか? いえ、普通によくやられています。実際に作った.soを見るとlibhello.aの内容が取り込まれています。 $ nm ../lib/libhello.a | grep T 0000000000000000 T __Z5helloRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE $ nm hello_wrap.cpython-37m-darwin.so | grep hello 0000000000001180 T _PyInit_hello_wrap 0000000000001110 T __Z10wrap_hellov 000000000000e800 T __Z5helloRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
kamontia

2020/06/20 16:16

シンボルテーブルの共有ありがとうございます。確かに定義されていますね。 私の方でも何とか期待する動作をさせることが出来ました。本当の原因、解決方法なのかはきちんと理解できてないのですが、静的ライブラリを作る際に「-fPIC」による再配置オプションをつけることで解決しました。 ただこれは静的ライブラリの作成を自分で実施できることが前提になるので、既存の静的ライブラリに「-fPIC」が指定されていない場合は解決できない問題となります。もう少し調べたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問