J'ai pu appeler une fonction C en Python, donc j'écrirai une note. Il existe plusieurs façons de créer un wrapper C, mais cette fois j'ai choisi Boost.Python.
Je l'ai installé en référence à cet article. La procédure est la suivante. (Environnement Mac, Python 3.7)
brew install boost-python3
Une fois installé, créez un lien vers le répertoire qui exécute le dylib de Boost.Python et Python lui-même dans / usr / local / Cellar /
.
ln -s /usr/local/Cellar/boost-python3/1.71.0_1/lib/libboost_python37.dylib /path/to/directory/libboost_python37.dylib
ln -s /usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/Python /path/to/directory/libpython3.7.dylib
pyconfig.h
ne peut pas être inclusLors de la première compilation J'ai eu une erreur fatale: pyconfig.h: aucun fichier ou répertoire de ce type, j'ai donc pu le résoudre en suivant les étapes ci-dessous.
(1) Vérifiez le chemin de Python comprend
python3.7-config --includes --libs
(2) Les informations suivantes s'affichent. Choisissez le premier (cet exemple est -I / usr / local / Cellar / python / 3.7.5 / Frameworks / Python.framework / Versions / 3.7 / include / python3.7m
)
-I/usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/include/python3.7m -I/home/victor/anaconda3/include/python3.7m -lpython3.7m -lpthread -ldl -lutil -lrt -lm
(3) Ajoutez la ligne suivante à ~ / .bashrc
avec le chemin excluant -I
:
~/.bashrc
export CPLUS_INCLUDE_PATH="$CPLUS_INCLUDE_PATH:/usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/include/python3.7m"
(4) Réfléchir
source ~/.bashrc
Hello World Boost.Python est une bibliothèque C ++, donc lorsque vous utilisez C, préparez C ++ séparément et incluez le contenu de C. Préparez les fichiers C, C ++, Python et Makefile:
my_c.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void hello_world();
my_c.c
#include "my_c.h"
void hello_world() {
printf("hello world\n");
}
my_cpp.cpp
#include <boost/python.hpp>
extern "C" {
#include "my_c.h"
}
using namespace boost::python;
BOOST_PYTHON_MODULE(my_wrapper){
def("hello_world", hello_world);
}
my_python.py
import my_wrapper
my_wrapper.hello_world()
Makefile
wrapper: my_cpp.cpp
gcc -c -o my_c.o my_c.c
g++ -c -o my_cpp.o my_cpp.cpp
g++ -fPIC -Wall -O2 -shared -o my_wrapper.so my_c.o my_cpp.o libboost_python37.dylib libpython3.7.dylib
Tu peux le faire avec ça
$ make
$ python my_python.py
hello world
S'il s'agit d'une fonction simple, aucun autre traitement n'est requis, mais s'il s'agit d'un type qui ne se connaît pas, la conversion semble nécessaire. Ce sera un exemple de code au lieu d'explication.
my_c.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int a;
int b;
}my_struct;
my_struct my_sum(my_struct *my_array, int len);
my_c.c
#include "my_c.h"
my_struct my_sum(my_struct *my_array, int len) {
my_struct sum = { 0 };
for(int i = 0; i < len; i++) {
sum.a += my_array[i].a;
sum.b += my_array[i].b;
}
return sum;
}
my_cpp.cpp
#include <boost/python.hpp>
extern "C" {
#include "my_c.h"
}
using namespace boost::python;
// boost::python::dict, boost::python::list, boost::python::len etc.
dict wrapper_sum(list py_list) {
int length = len(py_list);
my_struct ms[length];
for(int i = 0; i < length; i++) {
dict py_dict = extract<dict>(py_list[i]);
ms[i].a = extract<int>(py_dict["a"]);
ms[i].b = extract<int>(py_dict["b"]);
}
dict py_res;
my_struct c_res = my_sum(ms, length);
py_res["a"] = c_res.a;
py_res["b"] = c_res.b;
return py_res;
}
BOOST_PYTHON_MODULE(my_wrapper){
def("my_sum", wrapper_sum);
}
my_python.py
import my_wrapper
data = [
{
"a": 3,
"b": 9
},
{
"a": 1,
"b": 3
},
{
"a": 6,
"b": 2
},
{
"a": 0,
"b": 4
}
]
res = my_wrapper.my_sum(data)
print(res)
Je le ferai:
$ make
$ python my_python.py
{'a': 10, 'b': 18}
Avec un peu d'ingéniosité, la fonction écrite en C pour la vitesse est J'étais très heureux de pouvoir l'utiliser sans le réécrire en Python.
Recommended Posts