c/c++程序如何调用python函数
为了提高开发效率,扩展开发程序的功能,我们经常会在我们的linux c/c++进程里调用外部脚本, 例如lua、python,下面,介绍下如何在自己的linux c/c++代码里调用python脚本里的函数和类,并且将python库集成到我们自己的进程目录里,这样就不依赖系统环境是否存在python及其版本要求。
1、编译python库
我们首先可以从python官网下载需要的python版本,下载链接 https://www.python.org/ftp/python/2.7.5/Python-2.7.5.tgz,
这里下载的版本是python2.7.5, 下载后解压,解压命令:tar -xvf Python-2.7.5.tgz
进入解压目录,配置编译选项,可以通过./configure -h 查询配置选项,这里执行如下命令, --enable-shared保证生成动态库
./configure --prefix=/home/local --enable-optimizations --enable-shared
执行上述命令后, 就会在/home/local目录下生成python成果物
2、构建工程目录
将上面成果物里的lib目录和头文件目录拷贝到我们的工程中,如下图:
编译命令g++ -g main.cpp -L./lib -lpython2.7 -Wl,-rpath,./lib -std=c++11 -o prj, 这里需要链接libpython2.7.so,生成名为prj的可执行程序。执行./prj,会有如下输出:
注意:其实程序运行时,加载的libpython2.7.so依赖的python模块路径是/home/local下面的lib/python2.7/lib-dynload文件夹,而不是当前进程目录的python2.7, 我们需要添加环境变量,指定加载模块路径,可以设置
export PYTHONPATH=./lib/python2.7/lib-dynload/
也可以设置export PYTHONHOME=./, 这个优先级小于PYTHONPATH
其中my.py代码如下:
#!/usr/bin/python import json class ClassA: def HandleData(self, strJson): print "method param:",strJson jsonRoot = json.loads(strJson) jsonRet={} jsonRet["json1"]=jsonRoot jsonRet["json2"]="hero" a = json.dumps(jsonRet, indent=4) return a def HandleData(strJson1, strJson2): print "func param1:",strJson1," param2:", strJson2 json1 = json.loads(strJson1) json2 = json.loads(strJson2) jsonRet={} jsonRet["json1"]=json1 jsonRet["json2"]=json2 a = json.dumps(jsonRet, indent=4) return a
main.cpp代码如下
#include "python2.7/Python.h" #include "python2.7/frameobject.h" #include <string> void fetchPythonError() { PyObject* type = nullptr; PyObject* value= nullptr; PyObject* traceback = nullptr; PyErr_Fetch(&type, &value, &traceback); if (type) { printf("type: %s\n", PyExceptionClass_Name(type)); } if (value) { PyObject* line = PyObject_Str(value); if (line) { printf("value: %s\n", PyString_AsString(line)); } } if (traceback) { for (PyTracebackObject* tb = (PyTracebackObject*)traceback; tb != nullptr && tb->tb_frame != nullptr && tb->tb_frame->f_code != nullptr && tb->tb_frame->f_code->co_filename != nullptr && tb->tb_frame->f_code->co_name != nullptr; tb = tb->tb_next) { printf("File %s, line %d, in %s\n", PyString_AsString(tb->tb_frame->f_code->co_filename), tb->tb_lineno, PyString_AsString(tb->tb_frame->f_code->co_name)); } } } int main(int argc, char** argv) { Py_Initialize(); //虚拟机初始化 if (!Py_IsInitialized()) { fetchPythonError(); printf("Py_Initialize failed\n"); return -1; } PyEval_InitThreads(); //PyEval_ReleaseThread(PyThreadState_GET()); PyGILState_STATE state = PyGILState_Ensure(); PyRun_SimpleString("import sys"); PyRun_SimpleString("sys.path.append(\'./\')"); //加载当前路径下的所有py模块 PyGILState_Release(state); PyObject* pModule = PyImport_ImportModule("my");//导入模块 if (pModule == nullptr) { fetchPythonError(); printf("PyImport_ImportModule failed\n"); return -1; } PyObject* pDict = PyModule_GetDict(pModule);//模块的字典列表 if (pDict == nullptr) { fetchPythonError(); printf("PyModule_GetDict failed\n"); Py_DECREF(pModule); return -1; } /*调用功能函数*/ PyObject* pFunc = PyDict_GetItemString(pDict, "HandleData"); if (pFunc == nullptr || !PyCallable_Check(pFunc)) { fetchPythonError(); printf("PyDict_GetItemString failed,func: %s\n", "HandleData"); Py_DECREF(pDict); Py_DECREF(pModule); return -1; } std::string param1 = "{\"name\":\"hello\"}"; std::string param2 = "{\"xing\":\"world\"}"; PyObject* pReturn = PyObject_CallFunction(pFunc,"ss", param1.c_str(), param2.c_str()); char* pszResult = nullptr; PyArg_Parse(pReturn,"s", &pszResult); if (pszResult == nullptr) { return -1; } printf("func return :\n %s\n", pszResult); Py_DECREF(pReturn); Py_DECREF(pFunc); /*调用类成员method*/ PyObject* pClass = PyDict_GetItemString(pDict, "ClassA"); if (pClass == nullptr) { fetchPythonError(); printf("PyDict_GetItemString failed,class:%s\n", "ClassA"); Py_DECREF(pDict); Py_DECREF(pModule); return -1; } PyObject* pInstance = PyInstance_New(pClass, NULL, NULL); if (pInstance == nullptr) { fetchPythonError(); printf("PyInstance_New failed,class:%s\n", "ClassA"); Py_DECREF(pDict); Py_DECREF(pModule); return -1; } pReturn = PyObject_CallMethod(pInstance, "HandleData","s", param1.c_str()); PyArg_Parse(pReturn, "s", &pszResult); if (pszResult == nullptr) { return -1; } printf("func return :\n %s\n", pszResult); Py_DECREF(pReturn); Py_DECREF(pInstance); Py_DECREF(pClass); Py_DECREF(pDict); Py_DECREF(pModule); Py_Finalize();//关闭解释器 return 0; }