我尝试使用给定的intel复制问题,但是这是不可能的,因此我创建了一个小示例(尽可能接近问题中所描述的内容)-也称为[SO]:如何创建最小的,可复制的示例(reprex(mcve))(应该包含在问题
BTW中 )
因此,我在这里说明的问题是:
- C ++
- 加载 Python 引擎
- 加载一个 Python 模块
- 从该模块加载一个函数,该函数:
- 接收代表文件名的(字符串)参数
- 读取文件内容(文本)并返回
- 如果出现错误,只需返回文件名
- 调用该函数
- 获取函数调用结果
我正在使用(在 Win 10 x64(10.0.16299.125)上 ):
- Python 3.5.4 x64
- VStudio 2015社区版
该结构包括:
- VStudio 项目/解决方案
- 源文件( main00.cpp (从 main.cpp 重命名 ,但不想重新制作所有包含它的屏幕截图)) __
- Python 模块( experiment_test.py )
- 测试文件( test_file.txt )
main00.cpp :
#include <string>#include <iostream>#if defined(_DEBUG)# undef _DEBUG# define _DEBUG_UNDEFINED#endif#include <Python.h>#if defined(_DEBUG_UNDEFINED)# define _DEBUG# undef _DEBUG_UNDEFINED#endif#define MOD_NAME "experiment_test"#define FUNC_NAME "function_name"#define TEST_FILE_NAME "test_dir\test_file.txt"using std::cout;using std::cin;using std::endl;using std::string;int cleanup(const string &text = string(), int exitCode = 1) { Py_Finalize(); if (!text.empty()) cout << text << endl; cout << "Press ENTER to return...n"; cin.get(); return exitCode;}int main() { char c; string fName = TEST_FILE_NAME, result; PyObject *pName = NULL, *pModule = NULL, *pDict = NULL, *pFunc = NULL, *pArgs = NULL, *pValue = NULL, *pResult = NULL; Py_Initialize(); pName = PyUnipre_FromString(MOD_NAME); if (pName == NULL) { return cleanup("PyUnipre_FromString returned NULL"); } pModule = Pyimport_import(pName); Py_DECREF(pName); if (pModule == NULL) { return cleanup(string("NULL module: '") + MOD_NAME + "'"); } pDict = PyModule_GetDict(pModule); if (pDict == NULL) { return cleanup("NULL module dict"); } pFunc = PyDict_GetItemString(pDict, FUNC_NAME); if (pFunc == NULL) { return cleanup(string("module '") + MOD_NAME + "' doesn't export func '" + FUNC_NAME + "'"); } pArgs = PyTuple_New(1); if (pArgs == NULL) { return cleanup("NULL tuple returned"); } pValue = PyUnipre_FromString(fName.c_str()); if (pValue == NULL) { Py_DECREF(pArgs); return cleanup("PyUnipre_FromString(2) returned NULL"); } int setItemResult = PyTuple_SetItem(pArgs, 0, pValue); if (setItemResult) { Py_DECREF(pValue); Py_DECREF(pArgs); return cleanup("PyTuple_SetItem returned " + setItemResult); } pResult = PyObject_CallObject(pFunc, pArgs); Py_DECREF(pArgs); Py_DECREF(pValue); if (pResult == NULL) { return cleanup("PyObject_CallObject returned NULL"); } else { int len = ((PyASCIIObject *)(pResult))->length; char *res = PyUnipre_AsUTF8(pResult); Py_DECREF(pResult); if (res == NULL) { return cleanup("PyUnipre_AsUTF8 returned NULL"); } else { cout << string("C(++) - Python call: ") << MOD_NAME << "." << FUNC_NAME << "('" << fName << "') returned '" << res << "' (len: " << len << ")" << endl; } } return cleanup("OK", 0);}注意事项 :
开头的 DEBUG_ / __DEBUG_UNDEFINED_ 内容-在 调试 模式下构建时(与 _python35 _ d* .lib_ 相对),一个( lam )解决方法( gainarie )链接到 Release Python lib( python35.lib )- __ _ *_
如我所说,尝试简化代码(摆脱了 PyCallable_Check 测试)
尽管代码使用 _ C ++*_ 编译器,但很容易注意到它是用 _ C_ 风格编写的 _ *_
由于 Python的API ([Python.Docs]:Python嵌入在另一个应用程序)(都伸到/嵌入)使用指针,确保 测试 NULL 小号,否则有一个高的机会越来越 段错误 ( 访问冲突 )
添加了[Python.Docs]:参考计数-无效的Py_DECREF(PyObject * o)语句可避免内存泄漏
Build(编译/链接)/ Run选项(显然,您已经跳过了这些,因为您能够运行您的程序,但是无论如何我都会列出它们-确保在处理 多个选项 时这里有一些捷径这样的项目):
- 检查[SO]:CLR Windows窗体中的LNK2005错误(@CristiFati的答案)以获取构建 Win PE的 详细信息 __
- 为了加快构建依赖 Python的 项目时的速度,我创建了一个 VStudio用户宏 (称为 Python35Dir- 如下图所示,指向我的 Python 3.5 安装目录)
注意事项 :
* 路径(“ _c: Install x64 Python Python 3.5_ ”)指向从官方站点下载的安装* 显然,对于 _32bit_ ,必须相应地设置路径(设置为 _32bit_ _Python_ )* 该路径包含(按预期的方式)一个 _Release_ 版本,并且只要我不需要进入 _Python_ 代码(并且只要我不弄乱内存,就像(在 _Debug中_ 构建我的应用程序时),模式))。我的 _.exe中_ 有2个 _C运行时_ -检查下面的链接,查看篡改 _MSVC运行时_ ( _UCRT_ )会发生什么: __ __ __ * [[SO]:在库中使用fstream时,可执行文件中出现链接器错误(@CristiFati的回答)](https://stackoverflow.com/questions/8528437/when-using-fstream-in-a-library-i-get-linker-errors-in-the-executable/41558269#41558269) * [[SO]:链接到MS Visual C上的protobuf 3时出错(@CristiFati的回答)](https://stackoverflow.com/questions/35116437/errors-when-linking-to-protobuf-3-on-ms-visual-c/35118400#35118400) * 对于 _特殊_ 情况下,我已经建立 _的Python_ 在 _调试_ 模式,得到了二进制文件,但是这不是我的1日的选择,因为它需要设置(路径)改变* 编译:
让 VStudio 知道 Python 包含文件的位置:
* 链接:
让 VStudio 知道 Python 库文件的位置(如果只需要 pythonxx * .lib ( _ PYTHONCORE
),则不需要任何额外的操作,因为 _Python 代码默认包含 PYTHONCORE
;否则,所有其余的都应在[MS.Docs中](https://docs.microsoft.com/en-
us/cpp/build/reference/dot-lib-files-as-linker-
input)指定[]:.lib文件作为链接器输入:
__
* 运行/调试-让: * _VStudio_ 知道 _Python_ 运行时 _ **python35.dll**_ ( _PYTHONCORE_ )所在的位置( _%PATH%_ ) * 加载的 _Python_ 运行时知道其他模块的位置( _%PYTHONPATH%_ )
Experiment_test.py :
import osimport shutilimport precsdef function_name(file_name): print("Py - arg: '{}'".format(file_name)) if not os.path.isfile(file_name): return file_name with open(file_name, "rb") as f: content = f.read().depre() print("Py - Content len: {}, Content (can spread across multiple lines): '{}'".format(len(content), content)) return content注意事项 :
- 如开头所指定的几乎是虚拟的模块
- 工作 仅与 文本 文件( 解码 将失败 的二进制 文件)
- 导入未使用的模块,以确保它们正常(很明显,如果这样的 import 语句成功,则所有模块都应如此)
- 在 stdout 上打印一些数据(与 C ++ 端的数据匹配)
- 位于 Python 已知 __的路径中 (上一步中为 %PYTHONPATH% )
- 有1个参数( file_name )-与问题中没有任何参数的 关键区别 (不知道这是逻辑错误还是像 错字 )
test_dir test_file.txt :
line 0 - dummyline 1 - gainarie
输出 ( VStudio 控制台):
Py - arg: 'test_dirtest_file.txt'Py - Content len: 33, Content (can spread across multiple lines): 'line0 - dummy
line 1 - gainarie’
C(++) - Python call:
experiment_test.function_name(‘test_dirtest_file.txt’) returned ‘line 0 -
dummy
line 1 - gainarie’ (len: 33)
OK
Press ENTER to return…
最后说明 :
- 在这种情况下(简单的一种),使用安装路径中的 PYTHONCORE 。但是在其他版本( 例如 ,另一产品中附带的版本)中, 必须在 Py_Initialize 之前 通过 Py_SetPythonHome 设置 Python 的标准库路径 。 [SO]
虽然很旧,但运行Py_Initialize需要哪些文件?(@CristiFati的答案)可能包含一些有用的信息



