ShibokenはC++ライブラリからCPython用バインディングを生成するPySide付属のユーティリティです。本来はPySideプロジェクトが、QtのCPython用バインディングを作るためのツールですが他のC++ライブラリにも適用できます。
そこで、本記事ではShibokenを用いて既存のC++ライブラリのバインディングを作成し、それを用いるまでの手順を簡単に説明します。なお、環境はMac OS XでApple公式のPythonを用いています。
Shibokenの概要
Shibokenは次の3つから構成されています。
- API ExtractorはPySideで使われているバインディング生成ライブラリです。ライブラリヘッダを解析した情報と型情報が書かれたXMLファイルの情報を統合して、選択した言語のバインディングを生成します。
- Generator RunnerはAPI Extractorのコマンドラインフロントエンドです。
- ShibokenはC++ライブラリからCPython用バインディングを生成するGenerator Runnerプラグインです。
また、生成の過程を表したものが上の図です。設定ファイルや型情報ファイルを与えると、ヘッダファイル群を読み込んでPython用のバインディングが作られます。後はこれをコンパイルしてやればPythonで利用できるようになります。
libraw-liteのPythonバインディング作成
LibRaw-LiteはデジタルカメラのRawファイルを扱うためのC++ライブラリです。今回はこのライブラリをPythonで使えるようにします。
まずはライブラリを解凍して、コンパイルします。
> make
次に、libraw.h内のLibRaw::addmaskedborderstobitmap()はヘッダには宣言されていますが、定義が存在しないために削除します。 そうしなければ、pythonでimportしたときに次のようなエラーになります。
ImportError: dlopen(./libraw.so, 2): Symbol not found: __ZN6LibRaw28add_masked_borders_to_bitmapEv
Referenced from: /Users/foobar/src/LibRaw-Lite-0.7.2/python/libraw/libraw.so
Expected in: flat namespace
そして、shibokenがライブラリのヘッダファイルを簡単に取り込めるようにするため、必要なヘッダをまとめたファイルを作成します。
> ls libraw/*.h | awk '{printf("#include \"%s\"\n", $1)}' > shiboken.h
続いて、型情報を記述するためのファイルshiboken_typesystem.xmlを用意します。 これは次のようなファイルになっており、typesystemのpackageでは出力時のpythonのパッケージ名をlibrawを指定しています。また、primitive-typeは基本型を指定し、object-typeはC++の型をターゲット言語(ここではPython)にマッピングさせるようにしています。
1 2 3 4 5 6 7 8 9 10 11 12 | > cat shiboken_typesystem.xml <?xml version= "1.0" ?> <typesystem package= "libraw" > <primitive- type name= "char" /> <primitive- type name= "int" /> <primitive- type name= "float" /> <primitive- type name= "double" /> <primitive- type name= "unsigned" /> <primitive- type name= "unsigned int" /> <primitive- type name= "size_t" /> <object- type name= "LibRaw" /> < /typesystem > |
shiboken_binding.txtはshibokenのコマンドラインオプションを指定するファイルです。先の2ファイルを指定しています。
> cat shiboken_binding.txt
[generator-project]
header-file = shiboken.h
typesystem-file = shiboken_typesystem.xml
output-directory = python
generator-set = /usr/local/lib/generatorrunner/shiboken_generator.dylib
enable-parent-ctor-heuristic
use-isnull-as-nb_nonzero
これでとりあえずバインディングを生成することができます。わからない型を含む関数などは無視されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | > shiboken --project-file=shiboken_binding.txt (中略) Resolving typedefs... [WARNING] Fixing class inheritance... [WARNING] skipping function 'LibRaw::gamma_lut' , unmatched parameter type 'ushort[0x10000]' skipping function 'LibRaw::jpeg_thumb' , unmatched parameter type 'FILE*' skipping function 'LibRaw::write_ppm_tiff' , unmatched parameter type 'FILE*' skipping function 'LibRaw::dcraw_make_mem_thumb' , unmatched return type 'libraw_processed_image_t*' (中略) Detecting inconsistencies in class model... [OK] Detecting inconsistencies in typesystem... [OK] Done, 29 warnings (0 known issues) (後略) > cd python/libraw > ls libraw_abstract_datastream_wrapper.cpp libraw_output_params_t_wrapper.h libraw_abstract_datastream_wrapper.h libraw_processed_image_t_wrapper.cpp libraw_data_t_wrapper.cpp libraw_processed_image_t_wrapper.h libraw_data_t_wrapper.h libraw_python.h libraw_module_wrapper.cpp libraw_wrapper.cpp libraw_output_params_t_wrapper.cpp libraw_wrapper.h |
この出力されたソースを用いてPython拡張のための共有オブジェクトを作成します。
1 2 3 4 | > g++ -fPIC -I/System/Library/Frameworks/Python.framework/Headers \ -I/usr/local/include/shiboken -I../../libraw -bundle \ -o libraw.so *.cpp -undefined dynamic_lookup \ /usr/local/lib/libshiboken-python2.7.1.0.2.dylib ../../lib/libraw-lite.a |
これで、Libraw-Liteの一部の機能は利用できるようになります。次の例ではRawファイルを読み込んでその中に含まれるサムネイルを取り出しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | > file P5039940.ORF P5039940.ORF: data > python Python 2.6.6 (r266:84292, Jan 22 2011, 22:32:56) [GCC 4.2.1 (Apple Inc. build 5664)] on darwin Type "help" , "copyright" , "credits" or "license" for more information. >>> import libraw >>> dir(libraw) [ 'LibRaw' , '_Cpp_Api' , '__doc__' , '__file__' , '__name__' , '__package__' ] >>> r=libraw.LibRaw() >>> dir(r) [ 'FC' , '__class__' , '__delattr__' , '__dict__' , '__doc__' , '__format__' , '__getattribute__' , '__hash__' , '__init__' , '__new__' , '__reduce__' , '__reduce_ex__' , '__repr__' , '__setattr__' , '__sizeof__' , '__str__' , '__subclasshook__' , 'adjust_sizes_info_only' , 'cameraCount' , 'cameraList' , 'dcraw_document_mode_processing' , 'dcraw_ppm_tiff_writer' , 'dcraw_process' , 'dcraw_thumb_writer' , 'fc' , 'open_buffer' , 'open_file' , 'recycle' , 'strerror' , 'unpack' , 'unpack_function_name' , 'unpack_thumb' , 'verbose' , 'version' , 'versionNumber' ] >>> r.version() '0.7.2-Release(Lite)' >>> r.open_file( 'P5039940.ORF' ) 0 >>> r.unpack_thumb() 0 >>> r.dcraw_thumb_writer( 'thumb.jpg' ) 0 >>> exit () > file thumb.jpg thumb.jpg: JPEG image data, EXIF standard |
実際には、このままでは実行すると落ちてしまう (LibRaw.cameraListなど) 場合も多く、修正が必要です。
ただし、Shibokenでは、型システムファイル(shiboken_typesystem.xml)にそれらのソースの修正を書くことができるため、メンテナンス性も高くなっています。
なお、コード修正の方法についてはShibokenのマニュアルやShibokenソース内にあるサンプルファイルなどを参照してください。
まとめ
Shibokenを用いて既存のC++ライブラリのバインディングを作成して利用する方法を説明しました。
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。