自分用のメモ
以前に書いたやり方*1で入らなかったので,ここ*2を参考に手順を再構築
1. インストール
ここ*3からソースをダウンロード
boost ver.は以前に使っていた1.73.0
pythonはver.3.8を指定
$ sudo cp boost_1_73_0.tar.gz -r /opt/ $ cd /opt $ sudo tar zxvf boost_1_73_0.tar.gz $ sudo rm boost_1_73_0.tar.gz $ cd boost_1_73_0 $ sudo ./bootstrap.sh --with-libraries=python --with-python=python3 --with-python-version=3.8 $ sudo ./b2 --prefix=/opt/boost_1_73_0 install $ find /opt -name *boost_python*
$ find /opt -name *boost_numpy*
Note:
・よく分からなかったけど,以前には必要なかったオプション"--with-libraries=python --with-python=python3"が要るっぽかった.これが無いとlibboost_numpy38がビルドされない
・インストール先を"--prefix=/opt/boost_1_73_0 install"としているので/usr/libには入らない.多分,"-j8"オプションで汎用ディレクトリに入る
2. C言語ライブラリのビルド & Pythonからのコール
boost_sample.cpp
#include "boost/python/numpy.hpp" #include <stdexcept> #include <algorithm> #include <iostream> #include <fstream> #include <random> #include <sys/stat.h> namespace p = boost::python; namespace np = boost::python::numpy; using namespace std; np::ndarray multiply_matrix(np::ndarray a, np::ndarray b, int size) { int nd = a.get_nd(); if (nd != 1) { throw std::runtime_error("a must be 1-dimensional"); } if (a.get_dtype() != np::dtype::get_builtin<double>()) { throw std::runtime_error("a must be float64 array"); } double *A = reinterpret_cast<double *>(a.get_data()); nd = b.get_nd(); if (nd != 1) { throw std::runtime_error("b must be 1-dimensional"); } if (b.get_dtype() != np::dtype::get_builtin<double>()) throw std::runtime_error("b must be float64 array"); double *B = reinterpret_cast<double *>(b.get_data()); vector<double> ma; for(int i = 0; i < size; i++) { for(int j = 0; j < size; j++) { double tmp = 0.0; for(int k = 0; k < size; k++) { tmp += A[i*size + k]*B[k*size + j]; } ma.push_back(tmp); } } Py_intptr_t shape[2] = {size, size}; np::ndarray result = np::zeros(2, shape, np::dtype::get_builtin<double>()); std::copy(ma.begin(), ma.end(), reinterpret_cast<double*>(result.get_data())); return result; } double rand_uniform(double min, double max) { double width = max - min; std::random_device rnd; std::mt19937 mt(rnd()); std::uniform_int_distribution<> rand10000(0, 10000*width); int randi = rand10000(mt); double val = min + (float)randi/10000.0; return val; } int main(int argc, char* argv[]) { cout << "Hellow" << endl; Py_Initialize(); np::initialize(); double a[5*5]; double b[5*5]; int m_size = 5*5; for(int i = 0; i < 5; i++) { for(int j = 0; j < 5; j++) { a[i*5 + j] = rand_uniform(-1.0, 1.0); //random.uniform(-10.0, 10.0) b[i*5 + j] = rand_uniform(-1.0, 1.0); //random.uniform(-10.0, 10.0) } } cout << "input a:" << endl; cout << a[0] << "," << a[1] << "," << a[2] << "," << a[3] << "," << a[4] << endl; cout << a[5] << "," << a[6] << "," << a[7] << "," << a[8] << "," << a[9] << endl; cout << a[10] << "," << a[11] << "," << a[12] << "," << a[13] << "," << a[14] << endl; cout << a[15] << "," << a[16] << "," << a[17] << "," << a[18] << "," << a[19] << endl; cout << a[20] << "," << a[21] << "," << a[22] << "," << a[23] << "," << a[24] << endl; cout << "input b:" << endl; cout << b[0] << "," << b[1] << "," << b[2] << "," << b[3] << "," << b[4] << endl; cout << b[5] << "," << b[6] << "," << b[7] << "," << b[8] << "," << b[9] << endl; cout << b[10] << "," << b[11] << "," << b[12] << "," << b[13] << "," << b[14] << endl; cout << b[15] << "," << b[16] << "," << b[17] << "," << b[18] << "," << b[19] << endl; cout << b[20] << "," << b[21] << "," << b[22] << "," << b[23] << "," << b[24] << endl; p::tuple shape = p::make_tuple(m_size); p::tuple stride = p::make_tuple(sizeof(double)); np::dtype dt = np::dtype::get_builtin<double>(); np::ndarray a_np = np::from_data(&a[0], dt, shape, stride, p::object()); np::ndarray b_np = np::from_data(&b[0], dt, shape, stride, p::object()); np::ndarray result_np = multiply_matrix(a_np, b_np, 5); double *result = reinterpret_cast<double *>(result_np.get_data()); cout << "result:" << endl; cout << result[0] << "," << result[1] << "," << result[2] << "," << result[3] << "," << result[4] << endl; cout << result[5] << "," << result[6] << "," << result[7] << "," << result[8] << "," << result[9] << endl; cout << result[10] << "," << result[11] << "," << result[12] << "," << result[13] << "," << result[14] << endl; cout << result[15] << "," << result[16] << "," << result[17] << "," << result[18] << "," << result[19] << endl; cout << result[20] << "," << result[21] << "," << result[22] << "," << result[23] << "," << result[24] << endl; return 0; } BOOST_PYTHON_MODULE(libsample) { Py_Initialize(); np::initialize(); p::def("multiply_matrix", multiply_matrix); }
・mainとrand_uniformはデバッグ用
・”using namespace std”は普段使わないけど面倒かったので...
CMakeLists.txt
project(sample) cmake_minimum_required(VERSION 3.0) set(BOOST_ROOT /opt/boost_1_73_0) ### C++11 add_compile_options(-std=c++11) ### pkgconfig (for pkg_check_modules) find_package(PkgConfig REQUIRED) ### Python includes pkg_check_modules(PYTHON3 python3 REQUIRED) include_directories(${PYTHON3_INCLUDE_DIRS}) ### Boost includes include_directories(${BOOST_ROOT}/include) link_directories(${BOOST_ROOT}/lib) ### Build add_library(sample SHARED boost_sample.cpp) set_target_properties(sample PROPERTIES SUFFIX ".so") target_link_libraries(sample boost_numpy38 boost_python38)
boost_sample_call.py
import numpy as np import libsample as s import random if __name__ == "__main__": a = np.zeros([5, 5]) b = np.zeros([5, 5]) for i in range(5): for j in range(5): a[i, j] = random.uniform(-10.0, 10.0) b[i, j] = random.uniform(-10.0, 10.0) print(np.matmul(a, b)) result = s.multiply_matrix(a.reshape([5*5]), b.reshape(5*5), 5) print(result)
ビルドして実行
$ mkdir build $ cd build $ cmake .. $ make $ cd .. $ cp build/*.so ./ $ python3 boost_sample_call.py
3. C言語ソースのデバッグ
~/.bashrc
export LD_LIBRARY_PATH="/opt/boost_1_73_0/lib:$PATH"
task.json
{ "tasks": [ { "type": "shell", "label": "C/C++: g++-9 build active file", "command": "/usr/bin/g++-9", "args": [ "-fdiagnostics-color=always", "-g", "${file}", "-o", "${fileDirname}/${fileBasenameNoExtension}", "-std=c++11", "-I/opt/boost_1_73_0/include", "-I/usr/include/python3.8", "-I/usr/include/x86_64-linux-gnu/python3.8", "-L/usr/bin", "-lpython3.8", "-L/opt/boost_1_73_0/lib", "-lboost_numpy38", "-lboost_python38" ], "options": { "cwd": "${fileDirname}" }, "problemMatcher": [ "$gcc" ], "group": { "kind": "build", "isDefault": true }, "detail": "Task generated by Debugger." } ], "version": "2.0.0" }
・typeをcppbuild→shellにすること
・"-L/opt/boost_1_73_0/lib"で実際に入ったパスを指定すれば,/usr/libにライブラリが入らなくても問題ない
以上