Je pense qu'il est nécessaire d'étendre Python avec c ++ et de convertir le ndarray de Numpy en vecteur c ++. Boost :: python et boost :: python :: numpy sont utiles dans de tels cas. (Il semble que pybind11 soit également populaire ces jours-ci. Je voulais savoir tôt ...)
De plus, boost python peut en fait être construit en tant que fichier exécutable, vous pouvez donc le déboguer avec VSCode, par exemple.
Je vais expliquer à partir de 1 des packages nécessaires.
Remarques | ||
---|---|---|
OS | ubuntu 20.04 | Lancer sur docker |
python | 3.8.2 | |
boost | 1.73.0 | |
cmake | 3.16.3 |
Tout d'abord, installez les packages requis.
Les packages requis pour cet article étaient wget
, build-essential
, cmake
, python3-dev
et python3-pip
.
Veuillez installer selon votre environnement.
$ apt install wget build-essential cmake python3-dev python3-pip
Vérifiez également l'emplacement d'installation et la version de Python avec la commande suivante.
$ which python3
/usr/bin/python3
$ python3 --version
Python 3.8.2
Si vous souhaitez utiliser boost :: python :: numpy, vous devez installer numpy. (J'ai eu du mal à oublier cela.)
$ pip3 install numpy
Ensuite, téléchargez et installez boost. Installez en vous référant au chapitre 5 du document officiel suivant.
Comment démarrer Boost dans un environnement Unix page de téléchargement boost
Téléchargez boost, décompressez-le et allez dans le dossier décompressé.
$ wget (télécharger l'URL pour booster)
$ tar --bzip2 -xf boost_1_73_0.tar.bz2
$ cd boost_1_73_0
Préparez l'installation avec . / Bootstrap.sh
dans le dossier décompressé, puis compilez et installez avec. / B2
.
$ ./bootstrap.sh --with-libraries=python --with-python=python3 --with-python-version=3.8
$ ./b2 install -j8
En spécifiant --with-bibliothèques = python
, seul boost :: python
sera construit et installé, ce qui vous fera gagner du temps.
Spécifiez également la version de python confirmée précédemment avec --with-python-version
.
(Dans le cas d'un autre environnement tel qu'Anaconda ou pyenv, il semble que des paramètres supplémentaires soient nécessaires. Puisque cet article est construit dans un conteneur, je le fais avec la position que je peux polluer l'environnement autant que je veux.)
Par défaut, boost est installé sous / usr /
.
Vous pouvez trouver le répertoire d'inclusion et le chemin de la bibliothèque boost en utilisant la commande find
.
$ find /usr/ -name "*boost*" | grep include
/usr/include/c++/9/bits/boost_concept_check.h
/usr/local/include/boost
/usr/local/include/boost/chrono/typeof/boost
...
$ find /usr/ -name "*boost*" | grep lib
...
/usr/local/lib/cmake/boost_numpy-1.73.0/libboost_numpy-variant-static-py3.8.cmake
/usr/local/lib/cmake/boost_numpy-1.73.0/boost_numpy-config-version.cmake
/usr/local/lib/cmake/boost_numpy-1.73.0/libboost_numpy-variant-shared-py3.8.cmake
/usr/local/lib/libboost_numpy38.a
/usr/local/lib/libboost_python38.so.1.73
/usr/local/lib/libboost_numpy38.so.1.73
...
Créons un exemple de module qui a en fait une fonction qui renvoie la taille de la première dimension de ndarray.
sample.cpp
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
//Pour éviter les conflits d'espace réservé(Enquête requise)
#include <boost/python/numpy.hpp>
namespace py = boost::python;
namespace np = boost::python::numpy;
auto size(np::ndarray &a)
{
auto N = a.shape(0);
return N;
}
BOOST_PYTHON_MODULE(sample)
{
Py_Initialize();
np::initialize();
py::def("size", size);
}
Pour le compiler avec g ++
, exécutez la commande suivante:
g++ --shared -fPIC \
-I$BOOST_INCLUDE_DIR -I/usr/include/python3.8/ \
sample.cpp -Xlinker -rpath -Xlinker $BOOST_LIB_DIR \
-lboost_python38 -lboost_numpy38 -o sample.so
$ BOOST_INCLUDE_DIR
est le chemin d'inclusion de boost, $ BOOST_LIB_DIR
est le chemin de bibliothèque de boost, et je pense que cela dépend de l'environnement. Dans mon environnement, il s'agissait de / usr / local / include / boost /
et / usr / local / lib /
, respectivement, comme je l'ai confirmé en utilisant la commande find
plus tôt.
J'utilise CMake car je dois changer la commande en fonction de l'environnement et il est difficile de taper cette commande à chaque fois.
CMakeLists.txt
cmake_minimum_required(VERSION 3.12)
project(boost-python-test)
find_package(Python3 COMPONENTS Development)
find_package(Boost COMPONENTS python38 numpy38 REQUIRED)
#Pour le débogage: afficher le chemin résolu
message("## Boost_LIBRARIES: ${Boost_LIBRARIES}")
message("## Boost_INCLUDE_DIRS: ${Boost_INCLUDE_DIRS}")
message("## Python3_INCLUDE_DIRS: ${Python3_INCLUDE_DIRS}")
message("## Python3_LIBRARIES :${Python3_LIBRARIES}")
add_library(sample SHARED sample.cpp)
target_include_directories(sample PRIVATE ${Python3_INCLUDE_DIRS})
target_link_libraries(sample PRIVATE ${Boost_LIBRARIES} ${Python3_LIBRARIES})
# target_link_libraries(sample PRIVATE ${Boost_LIBRARIES})Cela fonctionne tout seul. La raison est inconnue.
set_target_properties(sample PROPERTIES PREFIX "") #préfixe'lib'Omettre
(Pour savoir comment utiliser g ++ et comment utiliser cmake
Etc. sont détaillés. Si vous regardez cela, vous pouvez tout voir, du mécanisme de compilation au mécanisme find_package
utilisé ci-dessus. Merci! )
Ensuite, placez ces «sample.cpp» et «CMakeLists.txt» dans la structure de répertoires suivante.
.
|-- CMakeLists.txt
|-- build
`-- sample.cpp
Construire dans construire.
$ cd build
$ cmake ..
$ cmake --build .
Il existe un fichier (bibliothèque partagée) appelé «sample.so» dans la construction qui le fait. Et si vous écrivez et exécutez le script python suivant dans la construction, il «importera» cette bibliothèque partagée et vous verrez que cela fonctionne bien.
test.py
import sample
import numpy as np
a = np.array([1,2,3,4], dtype=np.float32)
print(a)
size=sample.size(a)
print(size)
$ python3 test.py
[1. 2. 3. 4.]
4
Tant qu'il est appelé en tant que module python, il est difficile à déboguer et à utiliser, Si vous pouvez le construire en tant que fichier exécutable, vous pouvez utiliser CMake-Tools etc. de VS Code pour accélérer le débogage.
Création d'un environnement de développement C ++ avec des conteneurs distants de Visual Studio Code Préparez l'environnement de débogage distant VS Code en vous référant à. (Il existe également un Référentiel dont j'ai amélioré le référentiel de l'environnement dans l'article ci-dessus.)
Commencez par créer la structure de répertoires suivante sur cet environnement.
.
|-- CMakeLists.txt
|-- build
`-- main.cpp
CMakeLists.txt
cmake_minimum_required(VERSION 3.12)
project(boost-python-test)
find_package(Python3 COMPONENTS Development)
find_package(Boost COMPONENTS python38 numpy38 REQUIRED)
add_executable(main_app main.cpp)
target_include_directories(main_app PRIVATE ${Python3_INCLUDE_DIRS})
target_link_libraries(main_app PRIVATE ${Boost_LIBRARIES} ${Python3_LIBRARIES})
Si vous appelez Py_Initialize ()
et np :: initialize ()
au début de la fonction principale comme indiqué ci-dessous dans main.cpp
, vous pouvez le construire comme un fichier exécutable.
main.cpp
#include <iostream>
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
//Pour éviter les conflits d'espace réservé(Enquête requise)
#include <boost/python/numpy.hpp>
namespace py = boost::python;
namespace np = boost::python::numpy;
int main()
{
Py_Initialize();
np::initialize();
double v[] = {1.3 , 2.4 , -5.3};
int v_size = 3;
py::tuple shape = py::make_tuple(v_size);
py::tuple stride = py::make_tuple(sizeof(double));
np::dtype dt = np::dtype::get_builtin<double>();
np::ndarray output = np::from_data(&v[0], dt, shape, stride, py::object());
np::ndarray output_array = output.copy();
std::cout << "c++ array address::" << std::endl
<< std::hex << &v[0] << std::endl;
auto *p = reinterpret_cast<double*>(output.get_data());
std::cout << "ndarray address ::" << std::endl
<< std::hex << p << std::endl;
return 0;
}
Dans cet état, vous pouvez utiliser la fonction de débogage CMake-Tools de VSCode pour définir des points d'arrêt et examiner les variables. Si vous utilisez la CONSOLE DEBUG de VS Code comme indiqué dans l'image ci-dessous, vous pouvez gérer C ++ comme s'il s'agissait d'un langage d'interprétation, et le débogage sera plus rapide. Pratique!
Il y a des articles sur Qiita et des articles sur Boost :: python sur des sites externes, Il n'y avait pas d'article qui expliquait ce avec quoi j'étais coincé, ou comment utiliser le soi-disant cmake moderne comme mentionné dans cet article. J'ai donc fait cet article.
Tutoriel Boost.NumPy pour l'extension de Python en C ++ (pratique) Cet article utilise boost-numpy, mais boost-numpy a été intégré dans boost :: python et est désormais obsolète.
Créer une bibliothèque pour Python en C ++ Passer des tableaux numpy entre Python et C ++ Ces articles ont également été très utiles.
Recommended Posts