【发布时间】:2019-12-06 12:58:42
【问题描述】:
我正在使用以下代码从 C 调用 python 方法:
#include "Python.h"
char *find_site(void)
{
char *app_site_dir = 0;
PyObject *module = 0;
PyObject *result = 0;
PyObject *module_dict = 0;
PyObject *func = 0;
module = PyImport_ImportModule((char *)"Site"); /* new ref */
if (module == 0)
{
PyErr_Print();
printf("Couldn't find python module Site\n");
goto out;
}
printf("module = %p\n", module);
module_dict = PyModule_GetDict(module); /* borrowed */
if (module_dict == 0)
{
PyErr_Print();
printf("Couldn't find read python module Site\n");
goto out;
}
func = PyDict_GetItemString(module_dict, "find_site"); /* borrowed */
if (func == 0)
{
PyErr_Print();
printf("Couldn't find Site.find_site\n");
goto out;
}
result = PyEval_CallObject(func, NULL); /* new ref */
if (result == 0)
{
PyErr_Print();
printf("Couldn't run Site.find_site\n");
goto out;
}
else if (result == Py_None)
{
printf("Couldn't find site\n");
goto out;
}
printf("result = %p\n", result);
app_site_dir = PyString_AsString(result); /* borrowed */
if (app_site_dir == 0)
{
PyErr_Print();
printf("Couldn't read result from Site.find_site\n");
goto out;
}
app_site_dir = strdup(app_site_dir); /* keep in our own memory */
if (*app_site_dir)
{
printf("Found Site at %s\n", app_site_dir);
}
else
printf("Could not find Site\n");
out:;
printf("result = %p decref\n", result);
Py_XDECREF(result);
printf("module = %p module\n", module);
Py_XDECREF(module);
return app_site_dir;
}
int main(int argc, char **argv)
{
Py_Initialize();
char *site = find_site();
printf("Site = %s\n", site);
free(site);
}
python代码是
import os
def find_site():
return os.path.abspath(".")
(在完整的应用程序中,这更复杂,但这个简化的例子说明了问题)
这是在 linux 上使用 mxe.cc 交叉编译的,如下所示:
i686-w64-mingw32.static-c++ -I/usr/local/opt/mxe.master/usr/x86_64-w64-mingw32.static/include/python2.7 -o py32.exe py.cc -lpython27
它按预期在 Windows 上运行(来自 Ubuntu shell)
module = 028BC710
result = 0283D6B0
Found Site at \\wsl$\Ubuntu\home\dl
result = 0283D6B0 decref
module = 028BC710 decref
Site = \\wsl$\Ubuntu\home\dl
但是当编译为 64 位时
x86_64-w64-mingw32.static-c++ -I/usr/local/opt/mxe.master/usr/x86_64-w64-mingw32.static/include/python2.7 -o py64.exe py.cc -lpython27
运行失败:
module = 0000000002750408
result = 0000000000E62EF0
Found Site at \\wsl$\Ubuntu\home\dl
result = 0000000000E62EF0 decref
Python 调用成功,返回值并打印,但result 的XDECREF 失败,程序弹了出来,没有其他输出。
在这两种情况下,libpython 都是使用从目标 Windows 机器复制的 .dll 以及 pexports 和 dlltool 来创建 .a:例如
pexports-0.47/pexports python27.dll > python27.def
i686-w64-mingw32.static-dlltool --dllname python27.dll --def python27.def --output-lib libpython2.7.a
我的问题可能出在哪里?
【问题讨论】:
-
... 如果 python 的返回值为
return "C:/Test/Path"它可以工作。如果您添加test2 = test和return test2它会失败。如果你说test2 = "".join(c for c in path)和return test2它会失败。如果你设置path2 = "C:/Test/Path和return test2就可以了 -
使用
Py_REFCNT[在C 代码中] 显示return "c:/test"的值为2,但return test的值为1 -
在 python 2.7.17, 2.7.0, 2.6, 3.8 中完全相同的问题。
-
适用于 64 位 linux (Ubuntu/Bionic)
-
通过在我的应用程序中重新定义 Py_DECREF 宏:
#define Py_DECREF(op) do { if (--op->ob_refcnt == 0) fprintf(stderr, "DECREF %s %d %p %d %s %p\n", __FILE__, __LINE__, op, Py_SIZE(op), Py_TYPE(op)->tp_name,Py_TYPE(op)->tp_dealloc ); fflush(stderr); } while(0)输出如下行:DECREF vardef_file.cc 1601 0000000009F3C728 0 generator 0000000000000000似乎显示 tp_dealloc 是一个空指针。