C与Python互调(加Boost/numpy/cvxopt的配置)
近期需要使用C语言调用Python的功能。
目前需求是想让C++代码中 像调用C自己的函数一样调用Python的..
下面总结下如何成功搭建环境并实现功能
本人使用的环境及软件版本为:
win10 vs2015 Python3.65 boost1.66 [numpy1.13.3 cvxopt1.2.0]
(本人已自己的环境搭建 所以下面的对应版本 大家可以依据自己的版本雷同修改
建议使用和本人一样的版本 因为可能会避免版本不统一无法正常编译的问题
win10 vs2015这两个基本环境 不在这里累赘讲了..)
首先需要下载Python
python官网下载地址:https://www.python.org/downloads/windows/
(本人使用的python-3.6.5-amd64.exe)
1.1 下载时 注意对应自己的 x64 x86 几点几python的版本
(刚刚认真接触python 2.X和3.X简直是两种语言..网上的大部分代码有的是2.X有的是3.X 且两种不能一起编译.. 感觉对新人不太友好..)
1.2 安装时 如忘记设置Python的Path 安装完毕之后 自行在环境变量中添加也可以
(添加 有python36.dll对应的路径即可)
安装完Python之后 可以在vs中尝试下是否可以正常使用
配置Python环境如下
对应的头文件路径:
对应的库文件路径:
对应的依赖库名称:
(好像是不分debug 和 release)
配置好以上后随便找个代码测试:
// C代码: testPy.cpp
#include <Python.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
Py_Initialize();
// 将当前目录加入sys.path
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')");
// 导入hello.py模块
PyObject *pmodule = PyImport_ImportModule("hello");
if (!pmodule)
{
printf("can't find pytest.py");
return -1;
}
// 获得函数xprint对象,并调用,输出“hello world\n”
PyObject *pfunc = PyObject_GetAttrString(pmodule, "xprint");
PyObject_CallFunction(pfunc, NULL);
// 获得类Hello并生成实例pinstance,并调用print成员函数,输出“5 6\n”
PyObject *pclass = PyObject_GetAttrString(pmodule, "Hello");
PyObject *arg = Py_BuildValue("(i)", 5);
PyObject *pinstance = PyObject_Call(pclass, arg, NULL);
PyObject_CallMethod(pinstance, "print", "i", 6);
Py_DECREF(pmodule);
Py_DECREF(pfunc);
Py_DECREF(pclass);
Py_DECREF(arg);
Py_DECREF(pinstance);
// 关闭Python
Py_Finalize();
return 0;
}
# python代码:hello.py
class Hello:
def __init__(self, x):
self.a = x
def print(self, x=None):
print(x)
def xprint():
print("hello world")
if __name__ == "__main__":
xprint()
h = Hello(5)
h.print()
此时可能会出现几个问题:
a.程序报错类似下面的错误
_caffe.obj : error LNK2019: unresolved external symbol __imp__Py_NegativeRefcount referenced in function _import_array
_caffe.obj : error LNK2019: unresolved external symbol __imp__Py_Dealloc referenced in function _import_array
_caffe.obj : error LNK2001: unresolved external symbol __imp__Py_RefTotal
解决办法:找到python安装目录下的"pyconfig.h"文件, 进入修改
#ifdef _DEBUG
# define Py_DEBUG
#endif
为
#ifdef _DEBUG
//# define Py_DEBUG
#endif
保存即可.
b.程序找不到"python36_d.lib"文件.
解决方法:直接在Python安装目录下的libs目录中把对应的"python36.lib"额外拷贝出一个改名为"python36_d.lib".
c.程序无法找到"python36.dll".
解决方法:可能是环境变量的路径设置问题,直接检查并添加正确的path.如果路径设置没问题,尝试把对应的"*.dll"文件拷贝到代码对应的路径下,执行程序.如果此时木有问题应该就是路径的问题产生,尝试重启电脑或者修改环境变量吧..也没准啥也没改 过两天它醒过闷儿来就不报错了..
上面的a b c问题结果完毕之后 程序可以正常执行并显示:
hello world
6
此时Python算安装完毕,下面安装boost库
boost官方下载地址:https://www.boost.org/
(本人使用的boost_1_66_0.zip)
下载好对应的版本开始配置
1.解压到你高兴的路径下.
2.在".\tools\build"下双击"bootstrap.bat"文件,稍后会生成"bjam.exe"和"b2.exe"文件.
(之前在另一台电脑上双击"bootstrap.bat"文件会失败,原因不明中..)
3.把"bjam.exe"文件拷贝到 刚刚解压的boost主目录中.
4.开始进入重要环节------生成lib
在boost主目录中打开powershell 输入
.\bjam --with-python --toolset=msvc-14.0 threading=multi link=shared address-model=64 runtime-link=shared variant=debug
说明:
--with-python 指boost下的python模块 安装完毕之后还需要换成
--with-thread; --with-date_time; --with-system; --with-chrono各执行一遍
--toolset=msvc-14.0 编译器版本
threading=multi 使用多线程(multi) 或者 单线程(single)
link=shared 使用静态库(static)还是共享库(shared)
runtime-link=shared 运行时链接C/C++标准库时 使用静态库(static)还是共享库(shared)
variant=debug 决定编译debug模式 还是release模式
(本人编译的debug版本release下也可以用..可能是boost::python不分debug/release..)
生成的*.lib和*.dll文件会生成在 boost主目录下的 "stage"目录下
生成所有所需的lib之后 配置boost的环境
(include 和 lib的路径 在上面配置python的图片中)
这时开始执行可能会出现错误-----无法找到对应的*.lib 和 *.dll
解决办法同样是 把对应的*.lib改名成所需要的名称;把*.dll的path设置正确.
下面就可以执行简单的代码让C和Python牵手成功了..
// C代码 CP.cpp
#include <boost/python.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/python/call_method.hpp>
#include <vector>
#include <iostream>
#include <Python.h>
#include <string>
#include <boost/thread/thread.hpp>
boost::mutex io_mutex;
#include <boost/python/stl_iterator.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#include <fstream>
using namespace std;
namespace bp = boost::python;
template<typename T>
void python_to_vector(bp::object o, vector<T> &v) {
bp::stl_input_iterator<T> begin(o);
bp::stl_input_iterator<T> end;
v.clear();
v.insert(v.end(), begin, end);
}
template<class T>
bp::list std_vector_to_py_list(const std::vector<T>& v)
{
bp::object get_iter = bp::iterator<std::vector<T> >();
bp::object iter = get_iter(v);
bp::list l(iter);
return l;
}
template <class T>
bp::list toPythonList(std::vector<T> vector) {
typename std::vector<T>::iterator iter;
bp::list list;
for (iter = vector.begin(); iter != vector.end(); ++iter) {
list.append(*iter);
}
return list;
}
bool readData(std::string _path, std::vector<double> &_vec, int _rows, int _cols) {
std::ifstream infile(_path, std::ios::in);
if (!infile.is_open()) {
return false;
}
double temp;
_vec.push_back(_rows);
_vec.push_back(_cols);
while (!infile.eof()) {
infile >> temp;
_vec.push_back(temp);
}
return true;
}
void newPython() {
boost::mutex::scoped_lock
lock(io_mutex);
Py_Initialize();
try
{
bp::object module;
bp::object instance_ori;
bp::object instance;
vector<double> vec_ori_2DB;
vec_ori_2DB.push_back(1.0);
vec_ori_2DB.push_back(2.0);
// readData("data_2DB.txt", vec_ori_2DB, 24, 76);
vector<double> vec_ori_2DVd;
vec_ori_2DVd.push_back(3.5);
vec_ori_2DVd.push_back(5.5);
// readData("data_2DVd.txt", vec_ori_2DVd, 24, 1);
bp::list l_ori_Vd, l_ori_B;
l_ori_Vd = toPythonList(vec_ori_2DB);
l_ori_B = toPythonList(vec_ori_2DVd);
//l_ori = std_vector_to_py_list(vec_ori); // error
module = bp::import("Demo");
instance = module.attr("myAdd")(l_ori_Vd, l_ori_B);
bp::object obre = instance.attr("add")();
vector<double> res;
python_to_vector(obre, res);
for (int i = 0; i< res.size(); i++)
cout << res[i] << endl;
}
catch (...)
{
PyErr_Print();
PyErr_Clear();
}
}
int main()
{
Py_Initialize();
try
{
bp::object module = bp::import("sys");
bp::object pythonpath = module.attr("path");
}
catch (...)
{
PyErr_Print();
PyErr_Clear();
}
newPython();
return 0;
}
// Demo.py
class myAdd():
def __init__(self,data_Vd, data_B):
self.data_Vd = data_Vd
self.data_B = data_B
self.result=[]
def add(self): #__init__(self):
for i in range(len(self.data_Vd )):
x = self.data_Vd[i]+ self.data_B[i]
self.result.append(x)
return self.result
(此时需要注意 需要把*.py文件放在对应的*.exe可执行文件下 才可以正常导入)
运行结果:
4.5
7.5
接下来开始讲解本人需要使用的Python下的cvxopt库和numpy的配置,如客官对这个兴趣不足速速离场即可.
希望上面的东西可以帮到你!
安装cvxopt其实只要下载对的*.whl
cvxopt下载地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/#cvxopt
(本人使用的cvxopt版本为cvxopt-1.2.0-cp36-cp36m-win_amd64.whl)
numpy也可以在上面的网址上下载
(本人使用的numpy-1.13.3+mkl-cp36-cp36m-win_amd64.whl版本)
下载完毕之后把上面2个文件拷贝到Python主目录中,并在Python主目录中打开Powershell之后依次执行以下 a b c
a. .\python -m pip install numpy-1.13.3+mkl-cp36-cp36m-win_amd64.whl
b. .\python -m pip install -i https://pypi.douban.com/simple/ mkl
c. .\python -m pip install cvxopt-1.2.0-cp36-cp36m-win_amd64.whl
执行完以上3步之后点击python.exe
在输入 import numpy
和 import cvxopt
显示如下
代表 耶! 万事大吉! 一切顺利!
End..