From bd3d7329aea96ded66611d1a9d379b16fd7803f4 Mon Sep 17 00:00:00 2001 From: WiSo Date: Sat, 12 Mar 2011 19:05:18 +0100 Subject: [PATCH] Code changes to make external python work in windows. Changes credit to WiSo External pythong changes. Credit WiSo [WIN32] don't load python with our dll loader if USE_EXTERNAL_PYTHON is defined [WIN32] added osdefs.h for DELIM [WIN32] removed check for zlib.pyd. its in the core now [WIN32] unified log message [WIN32] set the PYTHONPATH within MSVCR90.DLL in order for python to pick it up [WIN32] external python doesn't need special wrapping and the path to the dll [WIN32] set some more python related env vars (might be removed from emu_msvcrt.cpp in future?) Fixed the error message for missing msvcrt dll so that it happens when the error condition occurrs. [WIN32] fixed: ext python should work now. Needs tests on win32 as I'm on win64 [WIN32] fixed: the putenv source got missing [WIN32] removed DetectDVDtype.* [WIN32] cosmetics There's no reason to make a special case for osx when looking to acquire the python thread lock prior to the Py_Initialize. [WIN32] added delayed loaded dlls to the opengl project target --- project/VS2010Express/XBMC.vcxproj | 9 +- project/VS2010Express/XBMC.vcxproj.filters | 7 +- xbmc/cores/DllLoader/Win32DllLoader.cpp | 9 +- xbmc/interfaces/python/XBPython.cpp | 36 ++++--- xbmc/win32/PlatformDefs.h | 1 + xbmc/win32/Win32DelayedDllLoad.cpp | 50 ++++----- xbmc/win32/win32env.cpp | 159 +++++++++++++++++++++++++++++ 7 files changed, 217 insertions(+), 54 deletions(-) create mode 100644 xbmc/win32/win32env.cpp diff --git a/project/VS2010Express/XBMC.vcxproj b/project/VS2010Express/XBMC.vcxproj index f72ff70..b58dd8d 100644 --- a/project/VS2010Express/XBMC.vcxproj +++ b/project/VS2010Express/XBMC.vcxproj @@ -1,4 +1,4 @@ - + @@ -126,7 +126,7 @@ $(OutDir)XBMC.exe ..\..\lib\libSDL-WIN32\lib;%(AdditionalLibraryDirectories) libc;msvcrt;libci;%(IgnoreSpecificDefaultLibraries) - dwmapi.dll;libmicrohttpd-5.dll;ssh.dll;%(DelayLoadDLLs) + dwmapi.dll;libmicrohttpd-5.dll;ssh.dll;sqlite3.dll;libsamplerate-0.dll;%(DelayLoadDLLs) true $(OutDir)XBMC.pdb Windows @@ -258,7 +258,7 @@ libc;msvcrt;libcmt;%(IgnoreSpecificDefaultLibraries) - dwmapi.dll;libmicrohttpd-5.dll;ssh.dll;%(DelayLoadDLLs) + dwmapi.dll;libmicrohttpd-5.dll;ssh.dll;sqlite3.dll;libsamplerate-0.dll;%(DelayLoadDLLs) true $(OutDir)XBMC.pdb Windows @@ -813,6 +813,7 @@ + @@ -2066,4 +2067,4 @@ - + \ No newline at end of file diff --git a/project/VS2010Express/XBMC.vcxproj.filters b/project/VS2010Express/XBMC.vcxproj.filters index 4f143cc..32e687b 100644 --- a/project/VS2010Express/XBMC.vcxproj.filters +++ b/project/VS2010Express/XBMC.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -2454,6 +2454,9 @@ win32 + + win32 + @@ -4928,4 +4931,4 @@ win32 - + \ No newline at end of file diff --git a/xbmc/cores/DllLoader/Win32DllLoader.cpp b/xbmc/cores/DllLoader/Win32DllLoader.cpp index 2ddab5a..b499639 100644 --- a/xbmc/cores/DllLoader/Win32DllLoader.cpp +++ b/xbmc/cores/DllLoader/Win32DllLoader.cpp @@ -428,16 +428,13 @@ bool FunctionNeedsWrapping(Export *exports, const char *functionName, void **fix bool Win32DllLoader::ResolveImport(const char *dllName, const char *functionName, void **fixup) { char *dll = GetName(); -#ifdef HAVE_LIBPYTHON2_6 - if (strstr(dll, "python26.dll") -#else - if (strstr(dll, "python24.dll") -#endif - || strstr(dll, ".pyd")) +#if !defined(USE_EXTERNAL_PYTHON) + if (strstr(dll, "python24.dll") || strstr(dll, ".pyd")) { // special case for python if (FunctionNeedsWrapping(win32_python_exports, functionName, fixup)) return true; } +#endif return FunctionNeedsWrapping(win32_exports, functionName, fixup); } diff --git a/xbmc/interfaces/python/XBPython.cpp b/xbmc/interfaces/python/XBPython.cpp index 2a5bcbb..c71ef86 100644 --- a/xbmc/interfaces/python/XBPython.cpp +++ b/xbmc/interfaces/python/XBPython.cpp @@ -41,9 +41,7 @@ #include "Util.h" #ifndef _LINUX -#if defined HAVE_LIBPYTHON2_6 -#define PYTHON_DLL "special://xbmcbin/system/python/python26.dll" -#else +#if !defined(USE_EXTERNAL_PYTHON) #define PYTHON_DLL "special://xbmcbin/system/python/python24.dll" #endif #else @@ -357,7 +355,7 @@ void XBPython::Initialize() m_iDllScriptCounter++; if (!m_bInitialized) { -#if (!(defined _LINUX && defined USE_EXTERNAL_PYTHON)) +#if !defined(USE_EXTERNAL_PYTHON) m_pDll = DllLoaderContainer::LoadModule(PYTHON_DLL, NULL, true); if (!m_pDll || !python_load_dll(*m_pDll)) @@ -375,9 +373,6 @@ void XBPython::Initialize() !FileExist("special://xbmc/system/python/DLLs/bz2.pyd") || !FileExist("special://xbmc/system/python/DLLs/pyexpat.pyd") || !FileExist("special://xbmc/system/python/DLLs/select.pyd") || -#ifndef HAVE_LIBPYTHON2_6 - !FileExist("special://xbmc/system/python/DLLs/zlib.pyd") || -#endif !FileExist("special://xbmc/system/python/DLLs/unicodedata.pyd")) { CLog::Log(LOGERROR, "Python: Missing files, unable to execute script"); @@ -421,6 +416,21 @@ void XBPython::Initialize() } setenv("PYTHONCASEOK", "1", 1); //This line should really be removed CLog::Log(LOGDEBUG, "Python wrapper library linked with system Python library"); +#elif defined(_WIN32) + // because the third party build of python is compiled with vs2008 we need + // a hack to set the PYTHONPATH + // buf is corrupted after putenv and might need a strdup but it seems to + // work this way + CStdString buf; + buf = "PYTHONPATH=" + _P("special://xbmc/system/python/DLLs") + ";" + _P("special://xbmc/system/python/Lib"); + pgwin32_putenv(buf.c_str()); + buf = "PYTHONOPTIMIZE=1"; + pgwin32_putenv(buf.c_str()); + buf = "PYTHONHOME=" + _P("special://xbmc/system/python"); + pgwin32_putenv(buf.c_str()); + buf = "OS=win32"; + pgwin32_putenv(buf.c_str()); + #endif /* USE_EXTERNAL_PYTHON */ if (PyEval_ThreadsInitialized()) @@ -434,15 +444,7 @@ void XBPython::Initialize() // If this is not the first time we initialize Python, the interpreter // lock already exists and we need to lock it as PyEval_InitThreads // would not do that in that case. -#if defined(__APPLE__) && defined(USE_EXTERNAL_PYTHON) - // grrr, we hang at PyEval_ThreadsInitialized after unloading/loading python - PyEval_InitThreads(); -#else - if (PyEval_ThreadsInitialized()) - PyEval_AcquireLock(); - else - PyEval_InitThreads(); -#endif + PyEval_AcquireLock(); char* python_argv[1] = { (char*)"" } ; PySys_SetArgv(1, python_argv); @@ -476,7 +478,7 @@ void XBPython::Finalize() { if (m_bInitialized) { - CLog::Log(LOGINFO, "Python, unloading python24.dll because no scripts are running anymore"); + CLog::Log(LOGINFO, "Python, unloading python shared library because no scripts are running anymore"); PyEval_AcquireLock(); PyThreadState_Swap((PyThreadState*)m_mainThreadState); diff --git a/xbmc/win32/PlatformDefs.h b/xbmc/win32/PlatformDefs.h index ff7d8b1..57cab8f 100644 --- a/xbmc/win32/PlatformDefs.h +++ b/xbmc/win32/PlatformDefs.h @@ -91,6 +91,7 @@ typedef unsigned long ThreadIdentifier; extern "C" char * strptime(const char *buf, const char *fmt, struct tm *tm); extern "C" int strverscmp (const char *s1, const char *s2); extern "C" char * strcasestr(const char* haystack, const char* needle); +extern int pgwin32_putenv(const char *envval); #endif // _WIN32 diff --git a/xbmc/win32/Win32DelayedDllLoad.cpp b/xbmc/win32/Win32DelayedDllLoad.cpp index 5fbbbf0..9a52902 100644 --- a/xbmc/win32/Win32DelayedDllLoad.cpp +++ b/xbmc/win32/Win32DelayedDllLoad.cpp @@ -30,31 +30,31 @@ FARPROC WINAPI delayHookNotifyFunc (unsigned dliNotify, PDelayLoadInfo pdli) switch (dliNotify) { case dliNotePreLoadLibrary: - if (stricmp(pdli->szDll, "libmicrohttpd-5.dll") == 0) - { - CStdString strDll = CSpecialProtocol::TranslatePath(DLL_PATH_LIBMICROHTTP); - HMODULE hMod = LoadLibraryEx(strDll.c_str(), 0, LOAD_WITH_ALTERED_SEARCH_PATH); - return (FARPROC)hMod; - } - if (stricmp(pdli->szDll, "ssh.dll") == 0) - { - CStdString strDll = CSpecialProtocol::TranslatePath("special://xbmcbin/system/ssh.dll"); - HMODULE hMod = LoadLibraryEx(strDll.c_str(), 0, LOAD_WITH_ALTERED_SEARCH_PATH); - return (FARPROC)hMod; - } - if (stricmp(pdli->szDll, "sqlite3.dll") == 0) - { - CStdString strDll = CSpecialProtocol::TranslatePath("special://xbmcbin/system/sqlite3.dll"); - HMODULE hMod = LoadLibraryEx(strDll.c_str(), 0, LOAD_WITH_ALTERED_SEARCH_PATH); - return (FARPROC)hMod; - } - if (stricmp(pdli->szDll, "libsamplerate-0.dll") == 0) - { - CStdString strDll = CSpecialProtocol::TranslatePath("special://xbmcbin/system/libsamplerate-0.dll"); - HMODULE hMod = LoadLibraryEx(strDll.c_str(), 0, LOAD_WITH_ALTERED_SEARCH_PATH); - return (FARPROC)hMod; - } - break; + if (stricmp(pdli->szDll, "libmicrohttpd-5.dll") == 0) + { + CStdString strDll = CSpecialProtocol::TranslatePath(DLL_PATH_LIBMICROHTTP); + HMODULE hMod = LoadLibraryEx(strDll.c_str(), 0, LOAD_WITH_ALTERED_SEARCH_PATH); + return (FARPROC)hMod; + } + if (stricmp(pdli->szDll, "ssh.dll") == 0) + { + CStdString strDll = CSpecialProtocol::TranslatePath("special://xbmcbin/system/ssh.dll"); + HMODULE hMod = LoadLibraryEx(strDll.c_str(), 0, LOAD_WITH_ALTERED_SEARCH_PATH); + return (FARPROC)hMod; + } + if (stricmp(pdli->szDll, "sqlite3.dll") == 0) + { + CStdString strDll = CSpecialProtocol::TranslatePath("special://xbmcbin/system/sqlite3.dll"); + HMODULE hMod = LoadLibraryEx(strDll.c_str(), 0, LOAD_WITH_ALTERED_SEARCH_PATH); + return (FARPROC)hMod; + } + if (stricmp(pdli->szDll, "libsamplerate-0.dll") == 0) + { + CStdString strDll = CSpecialProtocol::TranslatePath("special://xbmcbin/system/libsamplerate-0.dll"); + HMODULE hMod = LoadLibraryEx(strDll.c_str(), 0, LOAD_WITH_ALTERED_SEARCH_PATH); + return (FARPROC)hMod; + } + break; } return NULL; } diff --git a/xbmc/win32/win32env.cpp b/xbmc/win32/win32env.cpp new file mode 100644 index 0000000..450e9f9 --- /dev/null +++ b/xbmc/win32/win32env.cpp @@ -0,0 +1,159 @@ +/*------------------------------------------------------------------------- + * + * win32env.c + * putenv() and unsetenv() for win32, that updates both process + * environment and the cached versions in (potentially multiple) + * MSVCRT. + * + * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/port/win32env.c + * + *------------------------------------------------------------------------- + */ + +//#include "windows.h" + +int +pgwin32_putenv(const char *envval) +{ + char *envcpy; + char *cp; + + /* + * Each version of MSVCRT has its own _putenv() call in the runtime + * library. + * + * mingw always uses MSVCRT.DLL, but if we are in a Visual C++ + * environment, attempt to update the environment in all MSVCRT modules + * that are currently loaded, to work properly with any third party + * libraries linked against a different MSVCRT but still relying on + * environment variables. + * + * Also separately update the system environment that gets inherited by + * subprocesses. + */ +#ifdef _MSC_VER + typedef int (_cdecl * PUTENVPROC) (const char *name); + static struct + { + char *modulename; + HMODULE hmodule; + PUTENVPROC putenvFunc; + } rtmodules[] = + { + { + "msvcrt", 0, NULL + }, /* Visual Studio 6.0 / mingw */ + { + "msvcr70", 0, NULL + }, /* Visual Studio 2002 */ + { + "msvcr71", 0, NULL + }, /* Visual Studio 2003 */ + { + "msvcr80", 0, NULL + }, /* Visual Studio 2005 */ + { + "msvcr90", 0, NULL + }, /* Visual Studio 2008 */ + { + NULL, 0, NULL + } + }; + int i; + + for (i = 0; rtmodules[i].modulename; i++) + { + if (rtmodules[i].putenvFunc == NULL) + { + if (rtmodules[i].hmodule == 0) + { + /* Not attempted before, so try to find this DLL */ + rtmodules[i].hmodule = GetModuleHandle(rtmodules[i].modulename); + if (rtmodules[i].hmodule == NULL) + { + /* + * Set to INVALID_HANDLE_VALUE so we know we have tried + * this one before, and won't try again. + */ + rtmodules[i].hmodule = ((HMODULE)(LONG_PTR)-1); + continue; + } + else + { + rtmodules[i].putenvFunc = (PUTENVPROC) GetProcAddress(rtmodules[i].hmodule, "_putenv"); + if (rtmodules[i].putenvFunc == NULL) + { + CloseHandle(rtmodules[i].hmodule); + rtmodules[i].hmodule = ((HMODULE)(LONG_PTR)-1); + continue; + } + } + } + else + { + /* + * Module loaded, but we did not find the function last time. + * We're not going to find it this time either... + */ + continue; + } + } + /* At this point, putenvFunc is set or we have exited the loop */ + rtmodules[i].putenvFunc(envval); + } +#endif /* _MSC_VER */ + + /* + * Update the process environment - to make modifications visible to child + * processes. + * + * Need a copy of the string so we can modify it. + */ + envcpy = strdup(envval); + if (!envcpy) + return -1; + cp = strchr(envcpy, '='); + if (cp == NULL) + { + free(envcpy); + return -1; + } + *cp = '\0'; + cp++; + if (strlen(cp)) + { + /* + * Only call SetEnvironmentVariable() when we are adding a variable, + * not when removing it. Calling it on both crashes on at least + * certain versions of MingW. + */ + if (!SetEnvironmentVariable(envcpy, cp)) + { + free(envcpy); + return -1; + } + } + free(envcpy); + + /* Finally, update our "own" cache */ + return _putenv(envval); +} + +void +pgwin32_unsetenv(const char *name) +{ + char *envbuf; + + envbuf = (char *) malloc(strlen(name) + 2); + if (!envbuf) + return; + + sprintf(envbuf, "%s=", name); + pgwin32_putenv(envbuf); + free(envbuf); +} -- 2.7.4