工欲善其事,必先利其器
文章目录
- python 2.7
- 升级python 2.7到3.6
- 准备
- 编译&&安装
- 软连接
- .pro添加
- 静态库
- gcc -ldl 选项作用
- 动态链接库
- 准备
- 工程中配置
- demo && 解析
- C++调用py脚本
- C++向python传递参数
- 创建元组
- 示例
- 格式化字符
- 转换Python的返回值
- python调用C/C++
- python2的方法
- python3的方法
- reference
python 2.7
.pro文件添加
INCLUDEPATH += -I /usr/include/python2.7
LIBS += /usr/lib/x86_64-linux-gnu/libpython2.7.so
升级python 2.7到3.6
python -V
查看版本
准备
(1)首次安装需要先安装zlib*
sudo apt-get install zlib*
(2)下载并解压
官网下载
wget http://www.python.org/ftp/python/3.6.6/Python-3.6.6.tgz
我把下载的.tgz移到software,再打开终端输入命令解压
tar -xzvf Python-3.6.6.tgz
wget是一个下载文件的工具,用在命令行下。未指定目录情况下所下载的文件在home目录下
编译&&安装
在/usr/local目录新建一个文件夹python3
sudo -s
mkdir /usr/local/python3
到解压后的目录
./configure -prefix=/usr/local/python3
make
make install
加上–enable-shared和-fPIC之后可以将python3的动态链接库编译出来
./configure --prefix=/usr/local/python3 --enable-shared CFLAGS=-fPIC
软连接
先修改一下老版本的连接,修改后命令行输入python_old2 -V
,会看到旧版本的版本号
mv /usr/bin/python /usr/bin/python_old2
为python3创建新的软连接
ln -s /usr/local/python3/bin/python3 /usr/bin/python
python -V
,可以看到升级成功了
[python3采用编译动态链接库后]
python -V报错
python: error while loading shared libraries: libpython3.6m.so.1.0: cannot open shared object file: No such file or directory
复制该.so到/usr/lib
cp /usr/local/python3/lib/libpython3.6m.so.1.0 /usr/lib
后面才发现已经有python 3.5了
.pro添加
静态库
libpython3.6m.a,本方法有个报错没解决,故最终选用动态链接库
Qt Creator右键工程目录,Add library
DISTFILES += \
build-eye_tracking/testPython.py
unix:!macx: LIBS += -L$$PWD/../../../../usr/local/python3/lib/ -lpython3.6m
INCLUDEPATH += $$PWD/../../../../usr/local/python3/include/python3.6m
DEPENDPATH += $$PWD/../../../../usr/local/python3/include/python3.6m
unix:!macx: PRE_TARGETDEPS += $$PWD/../../../../usr/local/python3/lib/libpython3.6m.a
/usr/bin/ld: /home/ccl/Projects/eye_tracking/…/…/…/…/usr/local/python3/lib//libpython3.6m.a(dynload_shlib.o): undefined reference to symbol 'dlsym@@GLIBC_2.2.5’
加-ldl
,没解决
gcc -ldl 选项作用
如果你的程序中使用dlopen、dlsym、dlclose、dlerror 显示加载动态库,需要设置链接选项 -ldl
//如果动态库使用g++编译,那么动态库定义函数的时候加上extern “C”,否则会提示undefined symbol错误。
加载动态链接库,首先为共享库分配物理内存,然后在进程对应的页表项中建立虚拟页和物理页面之间的映射。
你可以认为系统中存在一种引用计数机制, 每当一个进程加载了共享库(在该进程的页表中进行一次映射),引用计数加一;
一个进程显式卸载(通过dlclose等)共享库或进程退出时,引用计数减 一,
当减少到0时,系统卸载共享库。
(1)打开动态链接库:dlopen,函数原型void *dlopen (const char *filename, int flag);
dlopen用于打开指定名字(filename)的动态链接库,并返回操作句柄。(2)取函数执行地址:dlsym,函数原型为: void *dlsym(void *handle, char *symbol);
dlsym根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的函数的执行代码地址。(3)关闭动态链接库:dlclose,函数原型为: int dlclose (void *handle);
dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。(4)动态库错误函数:dlerror,函数原型为: const char *dlerror(void);
当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。
//lib/x86_64-linux-gnu/libdl.so: error adding symbols: DSO missing from command line
追加 -lavutil 库便解决
动态链接库
准备
由于Qt中的slots
关键字与python重复,这里我们需要修改一下文件
/usr/local/python3/include/python3.6m/object.h,从
typedef struct{
const char* name;
int basicsize;
int itemsize;
unsigned int flags;
PyType_Slot *slots; /* terminated by slot==0. */
} PyType_Spec;
(用gedit查找PyType_Spec)改为
typedef struct{
const char* name;
int basicsize;
int itemsize;
unsigned int flags;
#undef slots // 这里取消slots宏定义
PyType_Slot *slots;/* terminated by slot==0. */
#define slots Q_SLOTS // 这里恢复slots宏定义与QT中QObjectDefs.h中一致
} PyType_Spec;
工程中配置
(1).pro添加
INCLUDEPATH += -I /usr/local/python3/include/python3.6m
LIBS += /usr/local/python3/lib/libpython3.6m.so
(2)头文件
#include <Python.h>
demo && 解析
C++调用py脚本
Add New…新建一个python文件,移到工程的构建目录下,/home/ccl/Projects/eye_tracking/build-eye_tracking
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def usePython():
print("2020/2/7")
print("Welcome to use Python in Qt")
def add(a,b):
print(a+b)
return a+b
//初始化Python解释器
Py_Initialize();
if (!Py_IsInitialized()) {
return;
}
/*************************************
* PyRun_SimpleString
把输入的字符串作为Python代码直接运行,返回0表示成功,-1表示有错。
大多时候错误都是因为字符串中有语法错误。
**************************************/
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')");//把当前路径加入python的默认搜索路路径
//导入一个Python模块,参数name可以是*.py文件的文件名,相当于import
PyObject* pModule = PyImport_ImportModule("testPython");//导入要调用的testPython.py
if (!pModule) {
qDebug()<<"cant open python file";
return;
}
/*************************************
* PyObject* PyObject_GetAttrString(PyObject *o, char*attr_name)
返回模块对象o中的attr_name 属性或函数,相当于Python中表达式语句,o.attr_name
**************************************/
PyObject* pFunHello = PyObject_GetAttrString(pModule,"usePython");
if (!pFunHello) {
qDebug("get function hello failed");
return;
}
//调用Python函数
PyObject_CallFunction(pFunHello,NULL);
PyObject* pFunAdd = PyObject_GetAttrString(pModule,"add");
if (!pFunAdd) {
qDebug("get function add failed");
return;
}
//两种调用方式
PyObject_CallFunction(pFunAdd,"(i,i)",5,7);
PyObject* pRet = PyEval_CallObject(pFunAdd,Py_BuildValue("(ii)",5, 7));
int result=0;
//解析python返回值
PyArg_Parse(pRet,"i", &result);
qDebug()<<"result="<<result;
//释放Python解释器所占用的资源
Py_Finalize();
C++向python传递参数
C++向Python传参数是以元组(tuple
)的方式
(1)PyEval_CallObject,参数为PyObject*
PyObject* PyEval_CallObject(PyObject* pfunc, PyObject* pargs)
(2)PyObject_CallFunction,直接设置格式和参数
PyObject * PyObject_CallFunction(PyObject *callable_object,const char *format, …);
PyObject_CallFunction(pFunAdd,"(i,i)",5,7);
PyEval_CallObject(pFunAdd,Py_BuildValue("(ii)",5, 7));
创建元组
(1)PyTuple_New
//用PyTuple_New()创建一个元组
PyObject* pyParams = PyTuple_New(2);
//设置参数
PyTuple_SetItem(pyParams,0, Py_BuildValue("i",5));
PyTuple_SetItem(pyParams,1, Py_BuildValue("i",7));
PyEval_CallObject(pFunc, pyParams);
(2)PyObject* Py_BuildValue(char *format, …)
直接使用Py_BuildValue构建
PyObject* pyParams = Py_BuildValue("(ii)",5, 7);
示例
Py_BuildValue("") //None
Py_BuildValue("i",123) //123
Py_BuildValue("iii",123, 456, 789) //(123, 456, 789)
Py_BuildValue("s","hello") //'hello'
Py_BuildValue("ss","hello", "world") //('hello', 'world')
Py_BuildValue("s#","hello", 4) //'hell'
Py_BuildValue("()") //()
Py_BuildValue("(i)",123) //(123,)
Py_BuildValue("(ii)",123, 456) //(123, 456)
Py_BuildValue("(i,i)",123, 456) //(123, 456)
Py_BuildValue("((ii)(ii))(ii)",1, 2, 3, 4, 5, 6) //(((1, 2), (3, 4)), (5, 6))
Py_BuildValue("[i,i]",123, 456) //[123, 456]
Py_BuildValue("{s:i,s:i}", "abc", 123, "def", 456) //{'abc': 123, 'def': 456}
格式化字符
转换Python的返回值
python返回的都是PyObject对象,常用PyArg_Parse解析,指定格式。如果返回为元组,则使用PyArg_ParseTuple
int result=0;
//解析python返回值
PyArg_Parse(pRet,"i", &result);
python调用C/C++
python2的方法
官网Extending Python with C or C++
//C部分
#define min(a,b) (((a) < (b)) ? (a) : (b))
char data[1024];
void SetData(const char *str)
{
//把str的内容复制到data中
strncpy(data, str, min(strlen(str) + 1, 1024));
}
const char *GetData()
{
return data;
}
封装成Python调用的函数,就是增加调用时解析 python传进来的参数的功能,再调用C的函数
static PyObject* PySetData(PyObject *self, PyObject *args)
{
const char* str = NULL;
//解析出参数到str
if ( !PyArg_ParseTuple(args, "s", &str) )
{
return 0;
}
SetData(str);
Py_RETURN_NONE;
}
static PyObject* PyGetData(PyObject *self, PyObject *args)
{
const char* str = NULL;
return PyString_FromString(GetData());
}
PyMethodDef
是一个C结构体,用来完成一个映射,也就是便于方法查找,把需要被外面调用的方法都记录在这表内。
结构体成员说明:
第一个字段:在 Python 里面使用的方法名;
第二个字段:C 模块内的函数名;
第三个字段:方法参数类型,是无参数(METH_NOARGS) , 还是有位置参数(METH_VARARGS), 还是其他等等;
第四个字段:方法描述,就是通过 help() 或者 doc 可以看到的;
需要注意的是,这个列表的最后必须以 {NULL, NULL, 0, NULL} 的形式来代表声明结束
//函数注释,使用print(pycallc.py_set_data.__doc__)可以查看
PyDoc_STRVAR(PySetData_doc__, "\
测试\n\
\n\
PySetData(str)\n\
str: 出入的字符串\n\
返回: \n\
null \n\
");
PyDoc_STRVAR(PyGetData_doc__, "\
打印数据\n\
\n\
PyGetData()\n\
返回: \n\
data \n\
");
static PyMethodDef module_methods[] = {
{"py_set_data", PySetData, METH_VARARGS, PySetData_doc__},
{"py_get_data", PyGetData, METH_VARARGS, PyGetData_doc__},
{NULL, NULL, 0, NULL}
};
生成模块,python文件中使用import pycallc
可以就可以使用了。
void InitCCallPy()
{
//Py_InitModule3在python3已被弃用
PyObject *module = Py_InitModule3("pycallc", module_methods,"python call c");
}
testPython.py里有import pycallc
,需在前面InitCCallPy()生成
testPython.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pycallc
def usePython():
print("2020/2/7")
print("Welcome to use Python in Qt")
def add(a,b):
print(a+b)
return a+b
def testC():
pycallc.py_set_data("change hello world!")
print 'in python : ',pycallc.py_get_data()
print(pycallc.py_set_data.__doc__)
python3的方法
Python 3.x中不再使用Py_InitModule
官网Extending Python with C or C++
reference
linux qt 调用python简单例子Qt+Python混合编程 windows
Qt下调用python OSX系统
C++调用Python浅析
PS:
PyQt5