为了找出这个问题,用了整天一天的时间来看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_InitalizeEx中initfsencoding(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; }
http://bugs.python.org/issue11320
http://docs.python.org/py3k/c-api/init.html#Py_SetPath