环境配置
以 Python38 为例,把 Python 的 include
和 lib
拷贝到自己的工程目录下:
1 2
| C:\Users\Administrator\AppData\Local\Programs\Python\Python38\include C:\Users\Administrator\AppData\Local\Programs\Python\Python38\libs
|
Python38 是 64 位的(x64),Python38-32 是 32 位的(x86)
注意是 libs 而不是 Lib
然后在工程中包括进去:
Visual Studio 项目属性 - 链接器 - 常规 - 附加库目录:libs
测试发现调用 Python 时项目只支持 x64 Release
错误解决
Debug 调用 Release lib
Debug 模式运行调用的是带 _d
后缀的库,无法找到。
include/config.h
中将 Python38_d.lib
改成 Python38.lib
。
或者把 libs 里面的 Python38.lib
改成 Python38_d.lib
。
无法解析的外部符号 __imp__Py_Initialize
这是由于调用的 Python 版本与活动解决方案平台的版本不一致导致的。
平台 x86(默认)对应 Python38_32 文件夹,x64 对应 Python38(默认64)文件夹。
应用程序无法正常启动(0xc000007b)
通常是 32 位的目标平台用了 64 位的 lib,或者反过来。
检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“0”不匹配值“2”
当前工程是 Debug 版本,而引用的库文件是 Release 版本,只需要把当前的 Debug 模式改成 Release 模式就可以了。
同样,如果检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0”,则说明是 Release 模式引用了 Debug 的库文件
检测到“RuntimeLibrary”的不匹配项: 值“MT_StaticRelease”不匹配值“MD_DynamicRelease”
项目右键 - 属性 - C/C++ - 代码生成 - 运行库,改成(Release 为 MT,Debug 为 MTD)
例子
Python:hello.py
(文件名就是导入的模块名)
1 2 3 4 5 6
| def Hello(): print("Hello World")
def _add(x, y): print('add', x, 'and', y) return x + y
|
C++:main.cpp
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 60 61 62 63 64
| #include <stdlib.h> #include <iostream>
#include "include\Python.h"
using namespace std;
int main(int argc, char* argv[]) { Py_Initialize();
PyRun_SimpleString("import sys"); PyRun_SimpleString("sys.path.append('./')");
PyObject* pModule = PyImport_ImportModule("hello"); if (!pModule) { cout << "Python get module failed." << endl; return -1; } cout << "Python get module succeed." << endl;
PyObject * pFunc = NULL; pFunc = PyObject_GetAttrString(pModule, "Hello"); PyEval_CallObject(pFunc, NULL);
PyObject* pv = PyObject_GetAttrString(pModule, "_add"); if (!pv || !PyCallable_Check(pv)) { cout << "Can't find funftion (_add)" << endl; return -1; } cout << "Get function (_add) succeed." << endl;
PyObject* args = PyTuple_New(2); PyObject* arg1 = PyLong_FromLong(4); PyObject* arg2 = PyLong_FromLong(3);
PyTuple_SetItem(args, 0, arg1); PyTuple_SetItem(args, 1, arg2);
PyObject* pRet = PyObject_CallObject(pv, args);
if (pRet) { long result = PyLong_AsLong(pRet); cout << "result:" << result << endl; }
Py_Finalize(); return 0; }
|
函数传参
1 2 3 4
| pFunc = PyObject_GetAttrString(pModule, "add"); PyObject *pArgs = PyTuple_New(2); PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", 5)); PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", 7));
|
返回值
1 2
| PyObject* pReturn = PyObject_CallObject(pv, args); PyArg_Parse(pReturn, "i", &result);
|
传递数组
1 2 3 4 5 6 7 8 9 10 11 12
| double array[] = { 1.2, 4.5, 6.7, 8.9, 1.5, 0.5 };
PyObject* pList = PyList_New(6); for (int i = 0; i < PyList_Size(pList); i++) { PyList_SetItem(pList, i, PyFloat_FromDouble(array[i])); }
PyObject* pArgs = PyTuple_New(1); PyTuple_SetItem(pArgs, 0, pList);
PyObject* pReturn = PyEval_CallObject(pFunc, pArgs);
|
Python代码处理
在发布软件的时候,通常我们都不希望代码可以直接被别人看到。
以上的 exe 要想能够单独运行,必须把 Python 脚本拷过去。为了不让别人能直接看到源码,可以拷过去生成的 .pyc
文件。