teleport/common/pyshell/src/pys_core.cpp

605 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <pys.h>
#include "pys_core.h"
#include "pys_util.h"
#ifdef PYS_USE_PYLIB_SHARED
//========================================================
// WIN32
//========================================================
#define DECLPROC(name) \
__PROC__ ## name pylib_ ## name = NULL;
#define GETPROCOPT(lib, name, sym) \
pylib_ ## name = (__PROC__ ## name)GetProcAddress(lib, #sym)
#define GETPROC(lib, name) \
GETPROCOPT(lib, name, name); \
if(!pylib_ ## name) { \
EXLOGE("[pys] can not GetProcAddress for " #name "\n"); \
return -1;\
}
#pragma warning(disable:4054)
#define DECLVAR(name) \
__VAR__ ## name* pylib_ ## name = NULL;
#define GETVAR(lib, name) \
pylib_ ## name = (__VAR__ ## name*)GetProcAddress(lib, #name); \
if (!pylib_ ## name) { \
EXLOGE("[pys] can not GetProcAddress for " #name "\n"); \
return -1; \
}
static int _pys_map_python_lib(DYLIB_HANDLE handle);
static DYLIB_HANDLE _pys_dlopen(const wchar_t* dylib_path);
static int pys_pylib_load(const wchar_t* lib_path)
{
DYLIB_HANDLE lib = NULL;
EXLOGD(L"[pys] py-lib: %ls\n", lib_path);
lib = _pys_dlopen(lib_path);
if (NULL == lib)
return -1;
if (0 != _pys_map_python_lib(lib))
return -1;
return 0;
}
DYLIB_HANDLE _pys_dlopen(const wchar_t* dylib_path)
{
DYLIB_HANDLE handle = NULL;
#ifdef EX_OS_WIN32
// PYSLOGW(L"[pys] py-lib: %ls\n", dylib_path);
handle = LoadLibraryExW(dylib_path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (NULL == handle)
{
EXLOGE(L"[pys] can not load python lib: %ls.\n", dylib_path);
return NULL;
}
#else
ex_astr path;
if (!ex_wstr2astr(dylib_path, path, EX_CODEPAGE_UTF8))
{
EXLOGE("[pys] convert dylib_path failed.\n");
return NULL;
}
EXLOGD("[pys] py-lib-a: %s\n", path);
handle = dlopen(path.c_str(), RTLD_NOW | RTLD_GLOBAL);
if (NULL == handle)
{
EXLOGE("[pys] dlopen() failed: %s.\n", dlerror());
return NULL;
}
#endif
return handle;
}
int _pys_map_python_lib(DYLIB_HANDLE handle)
{
GETVAR(handle, Py_DontWriteBytecodeFlag);
GETVAR(handle, Py_FileSystemDefaultEncoding);
GETVAR(handle, Py_FrozenFlag);
GETVAR(handle, Py_IgnoreEnvironmentFlag);
GETVAR(handle, Py_NoSiteFlag);
GETVAR(handle, Py_NoUserSiteDirectory);
GETVAR(handle, Py_OptimizeFlag);
GETVAR(handle, Py_VerboseFlag);
GETPROC(handle, Py_BuildValue);
GETPROC(handle, Py_DecRef);
GETPROC(handle, Py_Finalize);
GETPROC(handle, Py_IncRef);
GETPROC(handle, Py_Initialize);
GETPROC(handle, Py_SetPath);
GETPROC(handle, Py_SetProgramName);
GETPROC(handle, Py_SetPythonHome);
GETPROC(handle, PySys_SetArgvEx);
GETPROC(handle, PyImport_ImportModule);
GETPROC(handle, PyObject_GetAttrString);
//GETPROC(handle, _Py_char2wchar);
//GETPROC(handle, PyUnicode_FromWideChar);
GETPROC(handle, PyErr_Clear);
GETPROC(handle, PyErr_Occurred);
GETPROC(handle, PyErr_Print);
//GETPROC(handle, PyMem_RawFree);
GETPROC(handle, PyObject_Call);
GETPROC(handle, PyArg_Parse);
GETPROC(handle, PyObject_CallFunction);
GETPROC(handle, PyModule_GetDict);
GETPROC(handle, PyDict_GetItemString);
GETPROC(handle, PyDict_SetItemString);
GETPROC(handle, PyLong_AsLong);
GETPROC(handle, PyLong_FromLong);
GETPROC(handle, PyLong_FromUnsignedLong);
GETPROC(handle, PyLong_FromUnsignedLongLong);
GETPROC(handle, PyBytes_FromString);
GETPROC(handle, PyBytes_FromStringAndSize);
GETPROC(handle, PyUnicode_FromString);
GETPROC(handle, PyBool_FromLong);
GETPROC(handle, PyImport_ExtendInittab);
GETPROC(handle, PyModule_Create2);
GETPROC(handle, PyArg_ParseTuple);
GETPROC(handle, PyTuple_Pack);
return 0;
}
DECLVAR(Py_DontWriteBytecodeFlag);
DECLVAR(Py_FileSystemDefaultEncoding);
DECLVAR(Py_FrozenFlag);
DECLVAR(Py_IgnoreEnvironmentFlag);
DECLVAR(Py_NoSiteFlag);
DECLVAR(Py_NoUserSiteDirectory);
DECLVAR(Py_OptimizeFlag);
DECLVAR(Py_VerboseFlag);
DECLPROC(Py_BuildValue);
DECLPROC(Py_DecRef);
DECLPROC(Py_Finalize);
DECLPROC(Py_IncRef);
DECLPROC(Py_Initialize);
DECLPROC(Py_SetPath);
DECLPROC(Py_SetProgramName);
DECLPROC(Py_SetPythonHome);
DECLPROC(PySys_SetArgvEx);
DECLPROC(PyImport_ImportModule);
DECLPROC(PyObject_GetAttrString);
//DECLPROC(_Py_char2wchar);
//DECLPROC(PyUnicode_FromWideChar);
DECLPROC(PyErr_Clear);
DECLPROC(PyErr_Occurred);
DECLPROC(PyErr_Print);
//DECLPROC(PyMem_RawFree);
DECLPROC(PyObject_Call);
DECLPROC(PyArg_Parse);
DECLPROC(PyObject_CallFunction);
DECLPROC(PyModule_GetDict);
DECLPROC(PyDict_GetItemString);
DECLPROC(PyDict_SetItemString);
DECLPROC(PyLong_AsLong);
DECLPROC(PyLong_FromLong);
DECLPROC(PyLong_FromUnsignedLong);
DECLPROC(PyLong_FromUnsignedLongLong);
DECLPROC(PyBytes_FromString);
DECLPROC(PyBytes_FromStringAndSize);
DECLPROC(PyUnicode_FromString);
DECLPROC(PyBool_FromLong);
DECLPROC(PyImport_ExtendInittab);
DECLPROC(PyModule_Create2);
DECLPROC(PyArg_ParseTuple);
DECLPROC(PyTuple_Pack);
#else
int pys_pylib_load(const wchar_t* lib_path)
{
EXLOGD("[pys] link to python static lib.\n");
return 0;
}
#endif
//================================================================
//
//================================================================
namespace pys
{
BuiltinModuleInfo g_builtin_module_info;
BuiltinModuleInfo::BuiltinModuleInfo()
{}
BuiltinModuleInfo::~BuiltinModuleInfo()
{
builtin_module_infos::iterator it = m_infos.begin();
for (; it != m_infos.end(); ++it)
{
delete[] (*it)->method_def;
delete (*it)->module_def;
delete (*it);
}
m_infos.clear();
}
void BuiltinModuleInfo::add(PyMethodDef* method_def, PyModuleDef* module_def)
{
BUILTIN_MODULE_INFO* info = new BUILTIN_MODULE_INFO;
info->method_def = method_def;
info->module_def = module_def;
m_infos.push_back(info);
}
//================================================================
//
//================================================================
Core::Core()
{
m_init_tab = NULL;
}
Core::~Core()
{
if (NULL != m_init_tab)
delete[] m_init_tab;
}
bool Core::init(const wchar_t* exec_file, const wchar_t* runtime_path)
{
// if (!ex_exec_file(m_exec_file))
// return false;
m_exec_file = exec_file;
m_exec_path = m_exec_file;
if (!ex_dirname(m_exec_path))
return false;
m_runtime_path = runtime_path;
return _load_dylib();
}
bool Core::set_startup_file(const wchar_t* filename)
{
if (NULL == filename)
return false;
ex_wstr fname = filename;
if (!ex_is_abspath(fname.c_str()))
ex_abspath(fname);
if (!ex_is_file_exists(fname.c_str()))
return false;
ex_wstr ext;
if (!ex_path_ext_name(fname, ext))
return false;
m_start_file = fname;
if (ext == L"zip")
{
m_is_zipped_app = true;
// <20><>.zip<69>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><C2B7>
m_search_path.push_back(m_start_file);
}
else
{
m_is_zipped_app = false;
// <20><>.py<70>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><C2B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><C2B7>
ex_wstr tmp_path(m_start_file);
ex_dirname(tmp_path);
m_search_path.push_back(tmp_path);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><CEB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD><C4A3><EFBFBD><EFBFBD><EFBFBD>ƣ<EFBFBD><C6A3><EFBFBD><EFBFBD><EFBFBD>.py<70>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD>ģ<EFBFBD><C4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (m_bootstrap_module.empty())
{
ex_wstr wmod(m_start_file);
wmod.assign(m_start_file, tmp_path.length() + 1, m_start_file.length() - tmp_path.length() - 1 - 3);
ex_wstr2astr(wmod, m_bootstrap_module);
}
}
return true;
}
bool Core::add_builtin_module(const char* module_name, pys_init_module_func init_func)
{
builtin_modules::iterator it = m_builtin_modules.find(module_name);
if (it != m_builtin_modules.end())
return false;
m_builtin_modules.insert(std::make_pair(module_name, init_func));
return true;
}
bool Core::get_builtin_module_by_init_func(pys_init_module_func init_func, ex_astr& module_name)
{
builtin_modules::iterator it = m_builtin_modules.begin();
for (; it != m_builtin_modules.end(); ++it)
{
if (init_func == it->second)
{
module_name = it->first;
return true;
}
}
return false;
}
bool Core::_load_dylib(void)
{
#ifdef PYS_USE_PYLIB_SHARED
ex_wstr ver_file = m_runtime_path;
if (!ex_path_join(ver_file, true, L"python.ver", NULL))
return false;
FILE* f = pys_open_file(ver_file.c_str(), L"rb");
if (NULL == f)
{
EXLOGE(L"[pys] can not open file: %ls\n", ver_file.c_str());
return false;
}
fseek(f, 0L, SEEK_SET);
char dll_name[64] = { 0 };
size_t read_size = fread(dll_name, 1, 64, f);
fclose(f);
if (64 != read_size)
{
EXLOGE(L"[pys] read file failed, need 64B, read %dB\n", read_size);
return false;
}
ex_wstr wstr_dll;
if (!ex_astr2wstr(dll_name, wstr_dll))
return false;
ex_wstr dll_file = m_runtime_path;
if (!ex_path_join(dll_file, true, wstr_dll.c_str(), NULL))
return false;
if (0 != pys_pylib_load(dll_file.c_str()))
{
return false;
}
#endif
return true;
}
bool Core::add_search_path(const wchar_t* wpath)
{
ex_wstr wstr_path = wpath;
if (!ex_abspath(wstr_path))
{
EXLOGE(L"can not get abspath of `%ls`.\n", wpath);
return false;
}
pys_wstr_list::iterator it = m_search_path.begin();
for (; it != m_search_path.end(); ++it)
{
// TODO: windowsƽ̨<C6BD><CCA8><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD>Сд<D0A1>Ƚ<EFBFBD>
if (wstr_path == (*it))
return false;
}
m_search_path.push_back(wstr_path);
return true;
}
bool Core::add_search_path(const char* apath, int code_page)
{
ex_wstr wstr_path;
if (!ex_astr2wstr(apath, wstr_path, code_page))
return false;
return add_search_path(wstr_path.c_str());
}
bool Core::_run_prepare(void)
{
if(m_bootstrap_module.empty())
m_bootstrap_module = "pysmain";
if(m_bootstrap_func.empty())
m_bootstrap_func = "main";
#ifdef PYS_USE_PYLIB_SHARED
*pylib_Py_NoSiteFlag = 1;
*pylib_Py_OptimizeFlag = 2; // <20><><EFBFBD>в<EFBFBD><D0B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ż<EFBFBD><C5BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɲ<EFBFBD><C9B2><EFBFBD><EFBFBD>룬ȥ<EBA3AC><C8A5>assert<72><74>doc-string<6E><67>
*pylib_Py_FrozenFlag = 1;
*pylib_Py_DontWriteBytecodeFlag = 1; // <20><><EFBFBD>ڼ<EFBFBD><DABC>ص<EFBFBD>.py<70>ű<EFBFBD><C5B1><EFBFBD><EFBFBD>ڴ<EFBFBD><DAB4>б<EFBFBD><D0B1><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EBA3AC><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>.pyo<79><6F><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>
*pylib_Py_NoUserSiteDirectory = 1;
*pylib_Py_IgnoreEnvironmentFlag = 1;
*pylib_Py_VerboseFlag = 0;
#else
pylib_Py_NoSiteFlag = 1;
pylib_Py_OptimizeFlag = 2;
pylib_Py_FrozenFlag = 1;
pylib_Py_DontWriteBytecodeFlag = 1;
pylib_Py_NoUserSiteDirectory = 1;
pylib_Py_IgnoreEnvironmentFlag = 1;
pylib_Py_VerboseFlag = 0;
#endif
ex_wstr tmp_path = m_runtime_path;
ex_path_join(tmp_path, true, L"modules", NULL);
add_search_path(tmp_path.c_str());
tmp_path = m_runtime_path;
ex_path_join(tmp_path, true, L"python.zip", NULL);
add_search_path(tmp_path.c_str());
if (m_search_path.size() > 0)
{
pys_wstr_list::iterator it = m_search_path.begin();
for (; it != m_search_path.end(); ++it)
{
add_search_path(it->c_str());
}
}
return true;
}
void Core::_run_set_program(void)
{
if(m_prog_name.empty())
pylib_Py_SetProgramName((wchar_t*)m_exec_file.c_str());
else
pylib_Py_SetProgramName((wchar_t*)m_prog_name.c_str());
}
void Core::_run_set_path(void)
{
pys_wstr_list::iterator it = m_search_path.begin();
for (; it != m_search_path.end(); ++it)
{
if (!m_search_path_tmp.empty())
m_search_path_tmp += EX_PATH_SEP_STR;
m_search_path_tmp += (*it);
}
EXLOGD(L"[pys] search path: %ls\n", m_search_path_tmp.c_str());
pylib_Py_SetPath((wchar_t*)m_search_path_tmp.c_str());
}
void Core::_run_set_argv(void)
{
int tmp_argc = m_py_args.size();
wchar_t** tmp_wargv = (wchar_t**)calloc(tmp_argc + 1, sizeof(wchar_t*));
if (!tmp_wargv)
return;
int i = 0;
pys_wstr_list::iterator it = m_py_args.begin();
for (; it != m_py_args.end(); ++it)
{
tmp_wargv[i] = ex_wcsdup(it->c_str());
i++;
}
pylib_PySys_SetArgvEx(tmp_argc, tmp_wargv, 0);
ex_free_wargv(tmp_argc, tmp_wargv);
}
bool Core::_run_init_builtin_modules(void)
{
m_init_tab = NULL;
int cnt = m_builtin_modules.size();
if (0 == cnt)
return true;
m_init_tab = new struct _inittab[cnt + 1];
memset(m_init_tab, 0, sizeof(struct _inittab)*(cnt + 1));
int i = 0;
builtin_modules::iterator it = m_builtin_modules.begin();
for (; it != m_builtin_modules.end(); ++it, ++i)
{
m_init_tab[i].name = it->first.c_str();
m_init_tab[i].initfunc = it->second;
}
if (-1 == pylib_PyImport_ExtendInittab(m_init_tab))
{
EXLOGE("[pys] can not init builtin module.\n");
return false;
}
return true;
}
int Core::run(void)
{
int ret = 0;
PyObject* pModule = NULL;
PyObject* pDict = NULL;
PyObject* pFunc = NULL;
PyObject* pModuleName = NULL;
PyObject* pRunArgs = NULL;
PyObject* pyRet = NULL;
PYS_BOOL has_error = PYS_TRUE;
if (!_run_init_builtin_modules())
return PYSR_FAILED;
if (!_run_prepare())
return PYSR_FAILED;
_run_set_program();
_run_set_path();
// Py_Initialize()<29><><EFBFBD><EFBFBD><EFBFBD>ڳ<EFBFBD>ʼ<EFBFBD><CABC><EFBFBD>ڽ<EFBFBD>ģ<EFBFBD><C4A3>֮<EFBFBD><D6AE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
pylib_Py_Initialize();
_run_set_argv();
for (;;)
{
pModule = pylib_PyImport_ImportModule(m_bootstrap_module.c_str());
if (pModule == NULL)
{
EXLOGE("[pys] can not import module: %s\n", m_bootstrap_module.c_str());
ret = -1;
break;
}
pDict = pylib_PyModule_GetDict(pModule); /* NO ref added */
if (pDict == NULL)
{
EXLOGE("[pys] can not get module dict: %s\n", m_bootstrap_module.c_str());
ret = -1;
break;
}
pFunc = pylib_PyDict_GetItemString(pDict, (char*)m_bootstrap_func.c_str());
if (pFunc == NULL)
{
EXLOGE("[pys] module [%s] have no function named `%s`.\n", m_bootstrap_module.c_str(), m_bootstrap_func.c_str());
ret = -1;
break;
}
pyRet = pylib_PyObject_CallFunction(pFunc, "");
if (pyRet == NULL)
{
EXLOGE("[pys] %s.%s() return nothing.\n", m_bootstrap_module.c_str(), m_bootstrap_func.c_str());
ret = -1;
break;
}
pylib_PyErr_Clear();
ret = pylib_PyLong_AsLong(pyRet);
has_error = PYS_FALSE;
break;
}
if (pylib_PyErr_Occurred())
pylib_PyErr_Print();
pylib_PyErr_Clear();
if (pFunc) { PYLIB_DECREF(pFunc); }
if (pModule) { PYLIB_DECREF(pModule); }
if (pModuleName) { PYLIB_DECREF(pModuleName); }
if (pRunArgs) { PYLIB_DECREF(pRunArgs); }
if (pyRet) { PYLIB_DECREF(pyRet); }
pylib_Py_Finalize();
EXLOGD("[pys] python finalized. ExitCode=%d\n", ret);
return ret;
}
}