由于有用C++调用Python程序的需求,本文记录一种可行的方式,采用cpython打包库,在C++中加载解释器调用程序。
准备工作
安装CPython
示例过程
- 建立一个
.pyx
文件用于暴露接口。如example.pyx
1 2 3 4 5 6 7 8
|
cdef extern from "math.h": double sqrt(double x)
def c_sqrt(double x): return sqrt(x)
|
- 创建一个
setup.py
文件,用于构建Cython代码成为一个可被C++调用的扩展模块
1 2 3 4 5 6 7
| from setuptools import setup from Cython.Build import cythonize
setup( ext_modules=cythonize("example.pyx"), )
|
- 构建生成拓展模块
1
| python setup.py build_ext --inplace
|
此时会产生如下文件结构,example.cp39-win_amd64.pyd
这将是被我们调用的库。
- 建立
main.cpp
, 把main函数第一行的位置路径改为你的文件目录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| #include <Python.h> #include <iostream> #include <cstdlib>
int main() { _putenv("PYTHONHOME=E:\\conda\\envs\\cpy");
Py_Initialize();
PyObject *sysPath = PySys_GetObject("path"); PyList_Append(sysPath, PyUnicode_FromString("."));
PyObject* repr = PyObject_Repr(sysPath); PyObject* str = PyUnicode_AsEncodedString(repr, "utf-8", "~E~"); const char *bytes = PyBytes_AS_STRING(str); std::cout << "sys.path: " << bytes << std::endl; Py_XDECREF(repr); Py_XDECREF(str);
PyObject *pName, *pModule, *pFunc; PyObject *pArgs, *pValue;
pName = PyUnicode_DecodeFSDefault("example"); pModule = PyImport_Import(pName); Py_DECREF(pName);
if (pModule != NULL) { pFunc = PyObject_GetAttrString(pModule, "c_sqrt"); if (pFunc && PyCallable_Check(pFunc)) { pArgs = PyTuple_Pack(1, PyFloat_FromDouble(16.0)); pValue = PyObject_CallObject(pFunc, pArgs); Py_DECREF(pArgs); if (pValue != NULL) { std::cout << "Result of call: " << PyFloat_AsDouble(pValue) << std::endl; Py_DECREF(pValue); } else { PyErr_Print(); std::cerr << "Call failed" << std::endl; } } else { if (PyErr_Occurred()) PyErr_Print(); std::cerr << "Cannot find function 'c_sqrt'" << std::endl; } Py_XDECREF(pFunc); Py_DECREF(pModule); } else { PyErr_Print(); std::cerr << "Failed to load 'example'" << std::endl; }
Py_Finalize(); return 0; }
|
- 编译程序,这里要特别注意使用同一个python解释器环境,如果你使用虚拟环境,则应该把命令中的路径更改为你虚拟环境中的路径,
-lpython39
改为自己libs里面的动态库名称。
1
| g++ -o main main.cpp -IE:\conda\envs\cpy\include -LE:\conda\envs\cpy\libs -lpython39
|
这时运行程序可以看到已经成功运行了。
该封面图片由Kristen在Pixabay上发布