ビルドとテスト
David AbrahamsCopyright © 2002-2015 David Abrahams, Stefan Seefeld
必要事項
背景
C++ と Python を組み合わせるための基本的なモデルは 2 つある。
拡張。エンドユーザは Python のインタープリタ(実行可能ファイル)を起動し、C++ で書かれた Python の「拡張モジュール」をインポートする。ライブラリを C++ で書き Python のインターフェイスを与えることで、Python のプログラマが使用できるようにするという考え。Python からはこれらのライブラリは通常の Python モジュールと同じにしか見えない。
組み込み。エンドユーザは、Python をライブラリのサブルーチンとして呼び出す C++ で書かれたプログラムを起動する。既存のアプリケーションにスクリプト機能を追加するという考え。
拡張と組み込みの重要な違いは C++ の main
関数の場所である(それぞれ Python のインタープリタと他のプログラムである)。Python を他のプログラムへ組み込む場合であっても、拡張モジュールは C/C++ から Python のコードへアクセス可能にする最も優れた方法であり、拡張モジュールの使用が両方のモデルの核心であることに注意していただきたい。
わずかな例外を除いて、拡張モジュールは単一のエントリポイントを持ち動的に読み込まれるライブラリとしてビルドする。つまり変更時に他の拡張モジュールや main
を持つ実行可能ファイルを再ビルドする必要がない。
インストールなしのクイックスタート
Boost.Python を使い始めるのに「Boost をインストール」する必要はない。この説明では、バイナリを必要に応じてビルドする Boost.Build プロジェクトを利用する。最初のテストは Boost.Python のビルドより少し長くかかるかもしれないが、この方法であれば特定のコンパイラ設定に対してどのライブラリバイナリを使用すべきかといった厄介ごとに悩むことなく、正しいコンパイラオプションをあなた自身が理解できることだろう。
注釈
他のビルドシステムを使用して Boost.Python やその拡張をビルドすることは当然可能であるが、Boost では公式にはサポートしない。「Boost.Python がビルドできないよ」問題の 99% 以上は、以下の説明を無視して他のビルドシステムを使用したことが原因である。
それでも他のビルドシステムを使用したい場合は、以下の説明に従って bjam にオプション -a -o
filename
を付けて起動し実行するビルドコマンドをファイルにダンプすれば、あなたのビルドシステムで必要なことが分かる。
基本的な手順
Boost を入手する。Boost 導入ガイドの第 1 節、第 2 節を見よ。
bjam ビルドドライバを入手する。Boost 導入ガイドの第 5 節を見よ。
Boost をインストールした
example/quickstart/
ディレクトリに cd で移動する。小さなプロジェクト例がある。bjam を起動する。すべてのテストターゲットをビルドするため、導入ガイド第 5 節の起動例にある「
stage
」引数を「test
」に置き換える。またテストが生成した出力を見るため、引数に「--verbose-test
」を追加する。Windows の場合、bjam の起動は以下のようになる。
C:\\…\quickstart> bjam toolset=msvc --verbose-test test
Unix 系の場合はおそらく、
…/quickstart$ bjam toolset=gcc --verbose-test test
注釈
簡単のために、このガイドの残りの部分ではパス名に Windows ユーザになじみのあるバックスラッシュではなく、Unix スタイルのスラッシュを使用する。スラッシュはコマンドプロンプトウィンドウ以外のあらゆる場所で機能するはずである(コマンドプロンプトだけはバックスラッシュを使用しなければならない)。
ここまでの手順がうまくいったら、extending
という名前の拡張モジュールのビルドが終わり、test_extending.py
という Python スクリプトが走ってテストも完了しているはずである。また、Python を組み込む embedding という簡単なアプリケーションもビルド、起動する。
問題が起きた場合
コンパイラやリンカのエラーメッセージが大量に表示された場合、Boost.Build が Python のインストール情報を見つけられていない可能性が高い。bjam を起動する最初の数回、--debug-configuration
オプションを bjam に渡して Boost.Build が Python のインストール情報をすべて正しく見つけられているか確認することだ。失敗している場合は、以下の Boost.Build を設定するの節を試すとよい。
それでもなお問題が解決しない場合は、以下のメーリングリストに手助けしてくれる人がいるかもしれない。
Boost.Build に関する話題は Boost.Build のメーリングリスト
Boost.Python に固有の話題は Python の C++ Sig
すべて問題無い場合
おめでとう! Boost.Python に慣れていなければ、この時点でしばらくビルドに関することを忘れ、チュートリアルやリファレンスを通じてライブラリの学習に集中するとよいかもしれない。quickstart プロジェクトに変更を加えて、API について学んだことを十分に試してみるのもよい。
サンプルプロジェクトを変更する
拡張モジュールを(Boost ディストリビューション内の 1 つのソースファイルである)extending.cpp
内に限定し、これを extending
としてインポートすることに満足しているのであれば、ここでやめてしまってもよい。しかしながら少しぐらいは変更したいと思うことだろう。Boost.Build について詳しく学ぶことなく先に進む方法はある。
今ビルドしたプロジェクトは現在のディレクトリにある 2 つのファイルで規定されている。boost-build.jam
は Boost ビルドシステムのコードの場所を bjam に指定する。Jamroot
はビルドしたターゲットを記述する。これらのファイルにはコメントを大量に書いてあるので、変更は容易なはずである。ただし空白の保持には注意していただきたい。;
のような区切り文字は前後に空白がなければ bjam は認識しない。
プロジェクトの場所を変更する
Boost ディストリビューションに変更が生じないよう、このプロジェクトをどこか他の場所にコピーしたいと思うことだろう。単純に次のようにする。
example/quickstart/
ディレクトリ全体を新しいディレクトリにコピーする。boost-build.jam
およびJamroot
の新コピーにおいて、ファイルの先頭付近で相対パスを探し(コメントで分かりやすくマークしてある)、ファイルがexample/quickstart
ディレクトリ内の元の場所にあったときと同様に Boost ディストリビューションを指すように編集する。
http://www.boost.org/doc/libs/python/example/quickstart/boost-build.jam http://www.boost.org/doc/libs/python/example/quickstart/Jamroot
例えばプロジェクトを /home/dave/boost_1_34_0/libs/python/example/quickstart
から /home/dave/my-project
へ移動したとすると、boost-build.jam
の最初のパスは
../../../../tools/build/src
次のように変更する。
/home/dave/boost_1_34_0/tools/build/src
また Jamroot
の最初のパスは
../../../..
次のように変更する。
/home/dave/boost_1_34_0
新しいソースファイルを追加するか既存ファイルの名前を変更する
拡張モジュールや組み込みアプリケーションのビルドに必要なファイルの名前は、Jamroot
内にそれぞれ extending.cpp
、embedding.cpp
の右に並べて書く。各ファイル名の前後に空白を入れるのを忘れてはならない。
… file1.cpp file2.cpp file3.cpp …
当然ながら、ソースファイルの名前を変更したければ Jamroot
内の名前を編集して Boost.Build に通知する。
拡張モジュールの名前を変更する
拡張モジュールの名前は以下の 2 つで決まる。
Jamroot
内のpython-extension
直後の名前extending.cpp
内でBOOST_PYTHON_MODULE
に渡した名前
拡張モジュールの名前を extending
から hello
に変更するには、Jamroot
を編集して次の行を
python-extension extending : extending.cpp ;
以下のように変更する。
python-extension hello : extending.cpp ;
また extending.cpp
を編集して次の行を
BOOST_PYTHON_MODULE(extending)
以下のように変更する。
BOOST_PYTHON_MODULE(hello)
システムに Boost.Python をインストールする
Boost.Python は(ヘッダオンリーライブラリとは逆に)個別にコンパイルが必要なライブラリであるため、ユーザは Boost.Python ライブラリバイナリのサービスに依存する。
Boost.Python ライブラリのバイナリを普通にインストールする必要がある場合、Boost の導入ガイドを見ればその作成手順が一通り分かるだろう。ソースからバイナリをビルドする場合、Boost の全バイナリではなく Boost.Python のバイナリだけがビルドされるよう、bjam に --with-python
引数を(あるいは configure
に --with-libraries=python
引数を)渡すとよい。
Boost.Build を設定する
Boost.Build のリファレンスマニュアルにあるとおり、ビルドシステムで利用可能なツールとライブラリの指定はホームディレクトリの user-config.jam
で行う。user-config.jam
を作成・編集して Python の起動、ヘッダのインクルード、ライブラリのリンクについての方法を Boost.Build に指定する必要があるかもしれない。
注釈
Unix 系 OS のユーザ
Unix 系 OS を使用しており Boost の configure
スクリプトを走らせた場合、user-config.jam
が生成されている可能性がある。2 configure/make シーケンスが成功して Boost.Python のバイナリがビルドされていれば、user-config.jam
はおそらく既に正しい状態になっている。
Python を「標準的な」形でインストールしたのであれば、特に行うことはない。user-config.jam
で python を設定していない(かつ Boost.Build コマンドラインで --without-python
を指定していない)のであれば、Boost.Build は自動的に以下と等価なことを行い、最も適切な場所から Python を自動的に探し出す。
import toolset : using ;
using python ;
ただしこれが行われるのは Boost.Python のプロジェクトファイルを使用した場合だけである(例えば quickstart
の方法のように別のプロジェクトから参照される場合)。個別にコンパイルした Boost.Python バイナリにリンクする場合は、上に挙げた最小限のおまじないで user-config.jam
をセットアップしなければならない。
Python の設定引数
Python を複数バージョンインストールしている場合や Python を通常でない方法でインストールした場合は、以下の省略可能な引数のいずれか、またはすべてを using python
に与えなければならない可能性がある。
- version
使用する Python のバージョン。(メジャー).(マイナー)の形式でなければらない(例:
2.3
)。サブマイナーバージョンは含めてはならない(2.5.1
は不可)。複数のバージョンの Python をインストールした場合、大抵は version が省略不可能な唯一の引数となる。
- cmd-or-prefix
Python インタープリタを起動するコマンド。または Python のライブラリやヘッダファイルのインストール接頭辞。このパラメータの使用は、適切な Python 実行可能ファイルがない場合に限定すること。
- includes
Python ヘッダの
#include
パス。通常、version
とcmd-or-prefix
から適切なパスが推測される。
- libraries
Python ライブラリのバイナリへのパス。MacOS/Darwin では Python フレームワークのパスを渡してもよい。通常、
version
とcmd-or-prefix
から適切なパスが推測される。
- condition
指定する場合は、Boost.Build が使用する Python の設定を選択するときのビルド設定にマッチした Boost.Build パラメータの集合でなければならない。詳細は以下の例を見よ。
- extension-suffix
拡張モジュール名の真のファイル拡張子の前に追加する文字列。ほとんどの場合、この引数を使用する必要はない。大抵の場合、この接尾辞を使用するのは Windows において Python のデバッグビルドをターゲットにする場合だけであり、<python-debugging> 機能の値に基づいて自動的に設定される。しかしながら少なくとも 1 つの Linux のディストリビューション(Ubuntu Feisty Fawn)では python-dbg は特殊な設定がなされており、この種の接頭辞を使用しなければならない。
例
以下の例では大文字小文字の区別や、特に空白が重要である。
Python 2.5 と Python 2.4 の両方をインストールしている場合、
user-config.jam
を次のようにしておく。using python : 2.5 ; # 両方のバージョンの Python を有効にする using python : 2.4 ; # python 2.4 でビルドする場合は、python=2.4 を # コマンドラインに追加する。
最初のバージョン設定(2.5)が既定となる。Python 2.4 についてビルドする場合は bjam コマンドラインに
python=2.4
を追加する。Python を通常でない場所にインストールしている場合、
cmd-or-prefix
引数にインタープリタへのパスを与えるとよい。using python : : /usr/local/python-2.6-beta/bin/python ;
特定のツールセットに対して個別の Python ビルドを置いている場合、
condition
引数にそのツールセットを与えるとよい。using python ; # 通常のツールセットで使用 # Intel C++ ツールセットで使用 using python : # version : c:\\Devel\\Python-2.5-IntelBuild\\PCBuild\\python # cmd-or-prefix : # includes : # libraries : <toolset>intel # condition ;
Python のソースをダウンロードし、Windows 上でソースから通常版と「Python デバッグ」ビルド版の両方をビルドした場合、次のようにするとよい。
using python : 2.5 : C:\\src\\Python-2.5\\PCBuild\\python ; using python : 2.5 : C:\\src\\Python-2.5\\PCBuild\\python_d : # includes : # libs : <python-debugging>on ;
Windows でビルドした bjam では、Windows と Cygwin の両方の Python 拡張をビルド・テストできるよう
user-config.jam
をセットアップできる。Cygwin の Python インストールに対してcondition
引数に<target-os>cygwin
を渡すだけでよい。# Windows の場合 using python ; # Cygwin の場合 using python : : c:\\cygwin\\bin\\python2.5 : : : <target-os>cygwin ;
ビルドリクエストに
target-os=cygwin
と書くと、Cygwin 版の Python でビルドが行われる。3bjam target-os=cygwin toolset=gcc
他の方法でも同様に動作すると思う(Windows 版の Python をターゲットにして Cygwin 版の bjam を使用する場合)が、本稿執筆時点ではそのような組み合わせのビルドに対する Boost.Build ツールセットのサポートにはバグがあるようだ。
Boost.Build がターゲットを選択する方法が原因で、ビルドリクエストは完全に明確にしなければならないということに注意していただきたい。例えば、次のようであるとすると、
using python : 2.5 ; # 通常の Windows ビルドの場合 using python : 2.4 : : : : <target-os>cygwin ;
以下の方法でビルドするとエラーになる。
bjam target-os=cygwin
代わりに、こう書く必要がある。
bjam target-os=cygwin/python=2.4
Boost.Python ライブラリのバイナリを選択する
(Boost.Build に自動的に正しいライブラリを構築、リンクさせる代わりに)ビルド済みの Boost.Python ライブラリを使用する場合、どれをリンクするか考える必要がある。Boost.Python バイナリには動的版と静的版がある。アプリケーションに応じて注意して選択しなければならない。4
動的バイナリ
動的ライブラリは最も安全で最も汎用性の高い選択である。
与えられたツールセットでビルドしたすべての拡張モジュールが、ライブラリコードの単一のコピーを使用する。5
ライブラリには型変換レジストリが含まれる。すべての拡張モジュールが単一のレジストリを共有するので、ある動的に読み込んだ拡張モジュールで Python へエクスポートしたクラスのインスタンスを、別のモジュールでエクスポートした関数へ渡すことができる。
静的バイナリ
以下のいずれかの場合は Boost.Python の静的ライブラリを使用するのが適切である。
Python を拡張していて、動的に読み込んだ拡張モジュールで他の Boost.Python 拡張モジュールから使用する必要のない型をエクスポートしており、かつそれらの間でコアライブラリコードが複製されても問題ない場合。
Python をアプリケーションに組み込んでおり、かつ以下のいずれかの場合。
MacOS か AIX 以外の Unix 系 OS をターゲットにしていて、動的に読み込んだ拡張モジュールから実行可能ファイルの一部である Boost.Python ライブラリシンボルが「見える」場合。
またはアプリケーションに何らかの Boost.Python 拡張モジュールを静的にリンクしており、かつ動的に読み込んだ Boost.Python 拡張モジュールが静的にリンクした拡張モジュールでエクスポートした型を使用可能でも問題ない場合(あるいはその逆)。
#include
に関すること
Boost.Python を使用するプログラムの翻訳単位で直接
#include "python.h"
と書きたくなったら、代わりに#include "boost/python/detail/wrap_python.hpp"
を使用せよ。こうすることで Boost.Python を使用するのに必要ないくつかの事柄が適当に処理される(その中の 1 つを次節で見る)。wrap_python.hpp
の前にシステムヘッダをインクルードしないよう注意せよ。この制限は実際には Python によるものであり、より正確には Python とオペレーティングシステムの相互作用によるものである。詳細は http://docs.python.org/ext/simpleExample.html 6 を見よ。
Python のデバッグビルド
Python は特殊な「python debugging」設定でビルドすることで、拡張モジュールの開発者にとって非常に有用なチェックとインストゥルメント(instrumentation)を追加できる。デバッグ設定が使用するデータ構造は追加のメンバを含んでいるため、python debugging を有効にした Python 実行可能ビルドを、有効にせずにコンパイルしたライブラリや拡張モジュールとともに使用することはできない(その逆も同様である)。
Python のビルド済み実行可能の「python debugging」版はほとんどの Python ディストリビューションでは提供されておらず7、それらのビルドをユーザに強制したくないので、debug
ビルド(既定)において python debugging を自動的に有効化することはない。代わりに python-debugging
という特殊なビルドプロパティを用意しており、これを使用すると適切なプリプロセッサシンボルが定義され正しいライブラリがリンク先として選択される。
Unix 系プラットフォームでは、デバッグ版 Python のデータ構造は Py_DEBUG
シンボルを定義したときのみ使用される。多くの Windows コンパイラでは、プリプロセッサシンボル _DEBUG
を付けてビルドすると、Python は既定では Python DLL の特殊デバッグ版へのリンクを強制する。このシンボルは Python の有無とは別にごくありふれたものであるので、Boost.Python は boost/python/detail/wrap_python.hpp
で Python.h
をインクルードするときから BOOST_DEBUG_PYTHON
が定義されるまでの間、一時的に _DEBUG
を未定義にする。結論としては「python debugging」が必要で Boost.Build を使用しない場合は、BOOST_DEBUG_PYTHON
が定義されているのを確認することである。そうでなければ python debugging は無効になる。
Boost.Python をテストする
Boost.Build の完全なテストスイートを走らせるには、Boost ディストリビューションの test
サブディレクトリで bjam を起動する。
MinGW(および Cygwin の -mno-cygwin)の GCC ユーザに対する注意
Python の 2.4.1 より前のバージョンを MinGW の 3.0.0(binutils-2.13.90-20030111-1)より前のバージョンで使用する場合は、MinGW 互換バージョンの Python ライブラリを作成する必要がある(Python に付属のものは Microsoft 互換のリンカでしか動作しない)。『Python モジュールのインストール』の「拡張モジュールのビルド: 小技と豆知識」―「Windows で非 Microsoft コンパイラを使ってビルドするには」の節に従い、libpythonXX.a
を作成する。XX
はインストールした Python のメジャーバージョンとマイナーバージョン番号である。
- 1
Boost.Python の以前のバージョンと Python 2.2 の組み合わせでテストを行っており互換性を損なうようなことはしていないと考えている。しかしながら Boost.Python の最新版では Python の 2.4 より前のバージョンに対してテストを行っていない可能性があり、Python 2.2 および 2.3 をサポートしているとは 100% 言い切れない。
- 2
configure はホームディレクトリにある既存の
user-config.jam
について、(あれば)バックアップを作成した後で上書きする。- 3
<target-os>cygwin
機能は gcc ツール群の<flavor>cygwin
サブ機能とは別物であることに注意していただきたい。MinGW GCC もインストールしている場合は、両者を明示的に扱わなければならない。- 4
Boost.Python の静的ビルドと動的ビルドを区別する方法:
- 5
ほとんどの Unix/Linux 系プラットフォームでは動的に読み込んだオブジェクトを共有するため、異なるコンパイラツールセットでビルドした拡張モジュールを同一の Python インスタンスに読み込んだとき常に異なる Boost.Python ライブラリのコピーを使用するか定かではない。それらのコンパイラが互換性のある ABI を有しているのであれば、2 つのライブラリでビルドした拡張モジュールは相互運用可能なので、別のライブラリを使用しないほうが望ましい。そうでなければ拡張モジュールと Boost.Python はクラスレイアウト等が異なるため、大惨事となるかもしれない。何が起こるか確認する実験を行ってくれる人がいれば幸いである。
- 6
訳注 日本語訳は http://docs.python.jp/2/extending/extending.html#extending-simpleexample (Python 2.x の場合)。
- 7
Unix 系列のプラットフォームでは、debugging python と関連ライブラリは Python のビルド設定で
--with-pydebug
を追加するとビルドされる。Windows では Python のデバッグ版は、Python の完全なソースコードディストリビューションのPCBuild
サブディレクトリにある Visual Studio プロジェクトの「Win32 Debug」ターゲットから生成される。