`
gaofen100
  • 浏览: 1190264 次
文章分类
社区版块
存档分类
最新评论

Py_SetPath导致的BUG一例(issue11320)

 
阅读更多

为了找出这个问题,用了整天一天的时间来看Python的源码,不过还好,至少还熟悉了一下Python中这些杂乱的路径,并找到了原因。

issue11320 涉及的到就是Py_SetPath这个函数!

Manual中是这么介绍这个函数的:

void Py_SetPath(const wchar_t *)

Set the default module search path. If this function is called before Py_Initialize(), then Py_GetPath() won’t attempt to compute a default search path but uses the one provided instead. This is useful if Python is embedded by an application that has full knowledge of the location of all modules. The path components should be separated by semicolons.

此外:源码的注释中,也在建议使用这个函数:

 * An embedding application can use Py_SetPath() to override all of
 * these authomatic path computations.

起源

非常简单的一个程序:

#include "Python.h"
int main()
{
    Py_SetPath(L"/home/debao/Download/python/lib/python3.2/;"
               "/home/debao/Download/python/lib/python3.2/plat-linux2;"
               "/home/debao/Download/python/lib/python3.2/lib-dynload");
    Py_Initialize();
    PyRun_SimpleString("print(\'Hello C/C++\')");
    Py_Finalize();
    return 0;
}

额,为了调试的方便,我用的Qt Creator,使用的.pro文件如下:

CONFIG -=qt
SOURCES += test.cpp
INCLUDEPATH += ../include/python3.2m
LIBS += -L../lib -lpython3.2m -lpthread -ldl -lutil

编译,运行,结果出错:

  Fatal Python error: Py_Initialize: Unable to get the locale encoding
  LookupError: no codec search functions registered: can't find encoding

错误出在,Py_InitalizeExinitfsencoding(interp)一句,调试,调试,调试

最终发现Manual中说错了一句。路径中不是分号分割,而是用 冒号。准确一点,Windows下用分号,其他平台用冒号。

恩,我改

#include "Python.h"
int main()
{
    Py_SetPath(L"/home/debao/Download/python/lib/python3.2/:"
               "/home/debao/Download/python/lib/python3.2/plat-linux2:"
               "/home/debao/Download/python/lib/python3.2/lib-dynload");
    Py_Initialize();
    PyRun_SimpleString("print(\'Hello C/C++\')");
    Py_Finalize();
    return 0;
}

这下好了,上面的错误没有了,可是,错误信息更长了....

Traceback (most recent call last):
  File "/home/debao/Download/python/lib/python3.2/sysconfig.py", line 339, in _init_posix
    _parse_makefile(makefile, vars)
  File "/home/debao/Download/python/lib/python3.2/sysconfig.py", line 222, in _parse_makefile
    with open(filename, errors="surrogateescape") as f:
IOError: [Errno 2] No such file or directory: 'lib/python3.2/config-3.2m/Makefile'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/debao/Download/python/lib/python3.2/site.py", line 529, in <module>
    main()
  File "/home/debao/Download/python/lib/python3.2/site.py", line 517, in main
    known_paths = addusersitepackages(known_paths)
...

过程就不描述了,这个问题就是7个月前的issue11320所报告的。

原因

调用Py_SetPath会使得 sys.prefix 和 sys.exec_prefix 都为空。这点Manual中也提到了:

This also causes sys.executable to be set only to the raw program name (see Py_SetProgramName()) and for sys.prefix and sys.exec_prefix to be empty. 

可是,在sysconfig.py文件中,需要使用 sys.prefix 来找到一个配置用的 makefile 文件,而空串 sys.prefix 导致生成错误的文件路径名:lib/python3.2/config-3.2m/Makefile,因此该文件无法被找到。

Py_InitializeEx执行的后期,会导入 site.py 模块,而 site.py 模块需要 sysconfig.py 模块,从而导致这个问题。

如何解决?

不清楚这个bug如何解决,反正暂时在issue11320留下commit了,希望对官方解决这个问题能有帮助。

Py_SetPath目前是用不成了,不过还好,我们可以使用Py_SetPythonHome或者Py_SetProgramName。除此之外,环境变量也是可以用的,只是个人不太喜欢。

#include "Python.h"
int main()
{
#if 0
    Py_SetPythonHome(L"/home/debao/Download/python/");
#else
    Py_SetProgramName(L"/home/debao/Download/python/bin/python3");
#endif
    Py_Initialize();
    PyRun_SimpleString("print(\'Hello C/C++\')");
    Py_Finalize();
    return 0;
}

参考


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics