我已将 Python 嵌入到应用程序中,
foo.exe
。 当它运行时,Python 被调用并立即查找 Lib
。 我让它工作的唯一方法是将 Lib
(Python 的模块目录库)放在 foo.exe
的位置。
有没有办法可以将 Python 重定向到其他地方,例如
Python/Lib
? 我无法更改PATH
(这是Windows)并且我不想破解Python源代码。
基本上,我无法让 Py_SetPath() 工作,并且我无法在互联网上找到任何实际示例。
更新:
好的,这有效:
#define MYMAXPATHLEN 1000
static wchar_t progpath[MYMAXPATHLEN + 1];
wchar_t* pdir = L"\\My_New_Location\\Python\\Lib";
wchar_t* pdelim = L";";
wchar_t* pypath = NULL;
GetModuleFileNameW(NULL, progpath, MYMAXPATHLEN);
reduce(progpath);
wcscat(progpath,pdir);
// I get the present module path and add the extra dirs to access Lib code
wcscat(progpath, pdelim); // I add a path delimiter
pypath = Py_GetPath();
wcscat(progpath, pypath);
// I add the paths that Py_GetPath() produces.
Py_SetPath(progpath);
Py_Initialize();
我还调用 Py_SetProgramName(); Py_Initialize() 之后; 我不确定是否需要所有这些额外的东西,但较小的解决方案似乎失败了。
初始化后调用 Py_SetProgamName() 似乎对于嵌入调用正常工作非常重要。
我让它工作(在 Linux 上),执行以下操作:
// method to inspect PyObjects
static void reprint(PyObject *obj)
{
PyObject* repr = PyObject_Repr(obj);
PyObject* str = PyUnicode_AsEncodedString(repr, "utf-8", "~E~");
const char *bytes = PyBytes_AS_STRING(str);
printf("REPR: %s\n", bytes);
Py_XDECREF(repr);
Py_XDECREF(str);
}
.
int main()
{
// for our manually compiled and installed usr-local Python 3.6
//#define PATH L"/usr/local/bin:/usr/local/lib:/usr/local/lib/python3.6/lib-dynload"
//#define PREFIX L"/usr/local"
//#define EXEC_PREFIX L"/usr/local"
//#define FULL_PROG_PATH L"/usr/local/bin/python3.6"
// for apt installed Python 3.7
//#define PATH L"/usr/bin:/usr/lib:/usr/lib/python3.7/lib-dynload"
//#define PREFIX L"/usr"
//#define EXEC_PREFIX L"/usr"
//#define FULL_PROG_PATH L"/usr/bin/python3.7"
// for venv (which uses the /usr/local/lib python 3.6)
#define PATH L"/home/me/venv_dir/bin:/home/me/venv_dir/lib:/usr/local/lib/python3.6:/usr/local/lib/python3.6/lib-dynload"
#define PREFIX L"/home/me/venv_dir"
#define EXEC_PREFIX L"/usr/local"
#define FULL_PROG_PATH L"/usr/local/bin/python3.6"
// ------------------------------------------------
#define CHANGE_THE_INTERPRETER
#ifdef CHANGE_THE_INTERPRETER
// TODO : Look at using this: https://www.python.org/dev/peps/pep-0587/
Py_SetPath(PATH);
// change the built-in prefix/exec-prefix, in place.
wchar_t* wpPrefix = Py_GetPrefix();
wchar_t* wpExecPrefix = Py_GetExecPrefix();
wchar_t* wpProgramFullPath = Py_GetProgramFullPath();
wcscpy (wpPrefix, PREFIX);
wcscpy (wpExecPrefix, EXEC_PREFIX);
wcscpy (wpProgramFullPath, FULL_PROG_PATH);
#endif //CHANGE_THE_INTERPRETER
// inspect the environment variables. With the #define commented out above the "defaults" appear as indicated to the right hand side
wchar_t* xx; //defaults
xx = Py_GetPrefix(); //<prefix> L"/usr/local"
xx = Py_GetExecPrefix(); //<exec_prefix> L"/usr/local"
xx = Py_GetPath(); //L"/usr/local/lib/python36.zip:/usr/local/lib/python3.6:/usr/local/lib/python3.6:/usr/local/lib/python3.6/lib-dynload"
xx = Py_GetProgramName(); //L"python3"
xx = Py_GetPythonHome(); //null
xx = Py_GetProgramFullPath(); //<progpath> L"/usr/local/bin/python3"
Py_Initialize();
一些额外的内容
int x2 = PyRun_SimpleString ("import site; print (site.getsitepackages())");
int x3 = PyRun_SimpleString ("import datetime");
int x4 = PyRun_SimpleString ("import numpy as np");
//inspect sys info
PyObject* sys_executable = PySys_GetObject((char*)"executable"); reprint(sys_executable);
PyObject* sys_version = PySys_GetObject((char*)"version"); reprint(sys_version);
PyObject* sys_realPrefix = PySys_GetObject((char*)"real_prefix"); reprint(sys_realPrefix);
PyObject* sys_basePrefix = PySys_GetObject((char*)"base_prefix"); reprint(sys_basePrefix);
如果您查看 Python 模块
getpath.c
,您将看到以下缓冲区:
static wchar_t prefix[MAXPATHLEN+1];
static wchar_t exec_prefix[MAXPATHLEN+1];
static wchar_t progpath[MAXPATHLEN+1];
Py_GetProgramFullPath 等方法执行如下:
if (!module_search_path)
calculate_path();
return progpath;
...因此可以使用这些方法来获取缓冲区指针和
wcscpy
将值直接存入缓冲区。 注意,目前只有以这种方式实现 getpath 才可能实现!
需要lib-dynload
来确保可以拉入某些模块(例如日期时间)
另请注意,此方法可确保可以找到
.../python3.x/encodings
目录,从而防止 Py_Initialize 中出现运行时错误