本日は
Boost を使ってC++をPythonから呼び出したい.という願いを実現するために
の内容に従って次の組み合わせでトライしてみます,
- Visual Studio 2017
- Boost (1.66.0)
Boost の導入
-
http://www.boost.org/ にアクセス. ページ後半にあるダウンロードできるページに飛びます.
- boost_1_66_0.zip のダウンロードと展開
下の図にあるようにWindowsに対応するものをダウンロードします.
解凍したら簡単のためにCドライブの直下に置きます. - コマンドの実行
コマンドプロンプトを起動して次を実行します.
> bootstrap.bat
> b2 toolset=msvc threading=multi variant=debug,release link=static runtime-link=static address-model=64 --stagedir=stage/x64 -j 8
-j
はビルドに使うためのコア数に相当するようなので各自のPCの環境に応じて変更します.
その他のオプションなどは
boostの導入(Windows10,Visual Studio 2015)
が役に立ちそうです.
4. 生成物の確認
--stagedir=stage/x64
と指定していたのでライブラリなどの出力結果を確認します.
- libboost_numpy_....
- libboost_python3_....
のようなものがあれば幸せになります.
Visual Studio 2017の起動
以下プラットフォームを x64 構成を Release とした場合に限って説明します.
C++ -> 空のプロジェクト を選択しとりあえずプロジェクト名を callcfrompy
とします.この名前はPythonのモジュールとして使いたい名前を指定しておきます.この場合後で
import callcfrompy
のようにできます.
この後プロジェクトのプロパティの設定をしますが Pybind11で行ったような設定と似ている部分もあります.
See also
プロジェクトのプロパティの設定
構成プロパティ -> 全般に進み 次の項目を変更します.
C/C++ -> コード生成 において ランタイム ライブラリ
を マルチスレッド(/MT)
に変更.
VC++ ディレクトリ において インクルードディレクトリとライブラリディレクトリを各自の環境に合わせて設定.
私が追加したのはつぎのとおり:
- インクルードディレクトリ
- C:\boost_1_66_0
- C:\Miniconda3\include
- ライブラリディレクトリ
- C:\boost_1_66_0\stage\x64\lib
- C:\Miniconda3\libs
サンプルコードを書く
元ネタは C++でPythonを拡張するためのBoost.NumPyチュートリアル(実践編) からとのことなので引用します.
/*
Call C++ From Python
Reference:
http://tadaoyamaoka.hatenablog.com/entry/2017/05/25/234934
https://qiita.com/takuya-ki/items/3555ab17f9cea534e13b
https://qiita.com/termoshtt/items/81eeb0467d9087958f7f
*/
# define BOOST_PYTHON_STATIC_LIB
# define BOOST_NUMPY_STATIC_LIB
# include <boost/python/numpy.hpp>
# include <stdexcept>
# include <algorithm>
namespace p = boost::python;
namespace np = boost::python::numpy;
/* 2倍にする */
void mult_two(np::ndarray a) {
int nd = a.get_nd();
if (nd != 1)
throw std::runtime_error("a must be 1-dimensional");
size_t N = a.shape(0);
if (a.get_dtype() != np::dtype::get_builtin<float>())
throw std::runtime_error("a must be float32 array");
float *p = reinterpret_cast<float *>(a.get_data());
std::transform(p, p + N, p, [](float x) { return 2 * x; });
}
BOOST_PYTHON_MODULE(callcfrompy) {
Py_Initialize();
np::initialize();
p::def("mult_two", mult_two);
}
これをソースに追加してビルドします.
callcfrompy.pyd
なるものが生成されたらOKです.
あとはこれと同じディレクトリ上に下記の呼び出しコードを作ります.
from callcfrompy import mult_two
import numpy as np
def main():
arr = np.array([1, 2, 3, 4, 5]).astype(np.float32)
mult_two(arr)
print(arr)
if __name__ == '__main__':
main()
実行結果として配列の値が2倍になって入ればOKです.