From 0ea395ae964c9cd0f499e2ef0d0030c971201220 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 1 Dec 2017 20:50:58 +0100 Subject: [PATCH] bpo-32030: Add Python/pathconfig.c (#4668) * Factorize code from PC/getpathp.c and Modules/getpath.c to remove duplicated code * rename pathconfig_clear() to _PyPathConfig_Clear() * Inline _PyPathConfig_Fini() in pymain_impl() and then remove it, since it's a oneliner --- Include/internal/pystate.h | 4 + Include/pylifecycle.h | 1 - Makefile.pre.in | 3 +- Modules/getpath.c | 114 +---------------- Modules/main.c | 6 +- PC/getpathp.c | 119 +----------------- PCbuild/pythoncore.vcxproj | 1 + PCbuild/pythoncore.vcxproj.filters | 3 + Python/pathconfig.c | 189 +++++++++++++++++++++++++++++ Python/pylifecycle.c | 55 --------- 10 files changed, 204 insertions(+), 291 deletions(-) create mode 100644 Python/pathconfig.c diff --git a/Include/internal/pystate.h b/Include/internal/pystate.h index 50ad2fc83a3..9d8531965f1 100644 --- a/Include/internal/pystate.h +++ b/Include/internal/pystate.h @@ -52,6 +52,10 @@ typedef struct { #define _PyPathConfig_INIT {.module_search_path = NULL} +PyAPI_DATA(_PyPathConfig) _Py_path_config; + +PyAPI_FUNC(void) _PyPathConfig_Clear(_PyPathConfig *config); + /* Full Python runtime state */ diff --git a/Include/pylifecycle.h b/Include/pylifecycle.h index 3db88326aee..fa751692a66 100644 --- a/Include/pylifecycle.h +++ b/Include/pylifecycle.h @@ -105,7 +105,6 @@ PyAPI_FUNC(wchar_t *) Py_GetPath(void); #ifdef Py_BUILD_CORE PyAPI_FUNC(_PyInitError) _PyPathConfig_Init( const _PyMainInterpreterConfig *main_config); -PyAPI_FUNC(void) _PyPathConfig_Fini(void); #endif PyAPI_FUNC(void) Py_SetPath(const wchar_t *); #ifdef MS_WINDOWS diff --git a/Makefile.pre.in b/Makefile.pre.in index f425a89173a..14f6f8abc54 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -337,8 +337,9 @@ PYTHON_OBJS= \ Python/importdl.o \ Python/marshal.o \ Python/modsupport.o \ - Python/mystrtoul.o \ Python/mysnprintf.o \ + Python/mystrtoul.o \ + Python/pathconfig.o \ Python/peephole.o \ Python/pyarena.o \ Python/pyctype.o \ diff --git a/Modules/getpath.c b/Modules/getpath.c index 235badab230..8554dbe2a2c 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -132,7 +132,6 @@ typedef struct { static const wchar_t delimiter[2] = {DELIM, '\0'}; static const wchar_t separator[2] = {SEP, '\0'}; -static _PyPathConfig _Py_path_config = _PyPathConfig_INIT; /* Get file status. Encode the path to the locale encoding. */ @@ -1009,23 +1008,6 @@ calculate_path_impl(const _PyMainInterpreterConfig *main_config, } -static void -pathconfig_clear(_PyPathConfig *config) -{ -#define CLEAR(ATTR) \ - do { \ - PyMem_RawFree(ATTR); \ - ATTR = NULL; \ - } while (0) - - CLEAR(config->prefix); - CLEAR(config->exec_prefix); - CLEAR(config->program_full_path); - CLEAR(config->module_search_path); -#undef CLEAR -} - - /* Initialize paths for Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix() and Py_GetProgramFullPath() */ _PyInitError @@ -1049,7 +1031,7 @@ _PyPathConfig_Init(const _PyMainInterpreterConfig *main_config) err = calculate_path_impl(main_config, &calculate, &new_path_config); if (_Py_INIT_FAILED(err)) { - pathconfig_clear(&new_path_config); + _PyPathConfig_Clear(&new_path_config); goto done; } @@ -1061,100 +1043,6 @@ done: return err; } - -static void -pathconfig_global_init(void) -{ - if (_Py_path_config.module_search_path) { - /* Already initialized */ - return; - } - - _PyInitError err; - _PyMainInterpreterConfig config = _PyMainInterpreterConfig_INIT; - - err = _PyMainInterpreterConfig_ReadEnv(&config); - if (_Py_INIT_FAILED(err)) { - goto error; - } - - err = _PyMainInterpreterConfig_Read(&config); - if (_Py_INIT_FAILED(err)) { - goto error; - } - - err = _PyPathConfig_Init(&config); - if (_Py_INIT_FAILED(err)) { - goto error; - } - - _PyMainInterpreterConfig_Clear(&config); - return; - -error: - _PyMainInterpreterConfig_Clear(&config); - _Py_FatalInitError(err); -} - - -void -_PyPathConfig_Fini(void) -{ - pathconfig_clear(&_Py_path_config); -} - - -/* External interface */ -void -Py_SetPath(const wchar_t *path) -{ - if (path == NULL) { - pathconfig_clear(&_Py_path_config); - return; - } - - _PyPathConfig new_config; - new_config.program_full_path = _PyMem_RawWcsdup(Py_GetProgramName()); - new_config.exec_prefix = _PyMem_RawWcsdup(L""); - new_config.prefix = _PyMem_RawWcsdup(L""); - new_config.module_search_path = _PyMem_RawWcsdup(path); - - pathconfig_clear(&_Py_path_config); - _Py_path_config = new_config; -} - - -wchar_t * -Py_GetPath(void) -{ - pathconfig_global_init(); - return _Py_path_config.module_search_path; -} - - -wchar_t * -Py_GetPrefix(void) -{ - pathconfig_global_init(); - return _Py_path_config.prefix; -} - - -wchar_t * -Py_GetExecPrefix(void) -{ - pathconfig_global_init(); - return _Py_path_config.exec_prefix; -} - - -wchar_t * -Py_GetProgramFullPath(void) -{ - pathconfig_global_init(); - return _Py_path_config.program_full_path; -} - #ifdef __cplusplus } #endif diff --git a/Modules/main.c b/Modules/main.c index 4659c5d670b..6c1cf0d306a 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -1665,12 +1665,12 @@ pymain_impl(_PyMain *pymain) pymain->status = 120; } - /* _PyPathConfig_Fini() cannot be called in Py_FinalizeEx(). + /* _PyPathConfig_Clear() cannot be called in Py_FinalizeEx(). Py_Initialize() and Py_Finalize() can be called multiple times, but it must not "forget" parameters set by Py_SetProgramName(), Py_SetPath() or - Py_SetPythonHome(), whereas _PyPathConfig_Fini() clear all these + Py_SetPythonHome(), whereas _PyPathConfig_Clear() clear all these parameters. */ - _PyPathConfig_Fini(); + _PyPathConfig_Clear(&_Py_path_config); return 0; } diff --git a/PC/getpathp.c b/PC/getpathp.c index f8cfd7e6978..3a0ebc10636 100644 --- a/PC/getpathp.c +++ b/PC/getpathp.c @@ -130,9 +130,6 @@ typedef struct { } PyCalculatePath; -static _PyPathConfig _Py_path_config = _PyPathConfig_INIT; - - /* determine if "ch" is a separator character */ static int is_sep(wchar_t ch) @@ -1061,23 +1058,6 @@ calculate_free(PyCalculatePath *calculate) } -static void -pathconfig_clear(_PyPathConfig *config) -{ -#define CLEAR(ATTR) \ - do { \ - PyMem_RawFree(ATTR); \ - ATTR = NULL; \ - } while (0) - - CLEAR(config->prefix); - CLEAR(config->program_full_path); - CLEAR(config->dll_path); - CLEAR(config->module_search_path); -#undef CLEAR -} - - /* Initialize paths for Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix() and Py_GetProgramFullPath() */ _PyInitError @@ -1108,110 +1088,13 @@ _PyPathConfig_Init(const _PyMainInterpreterConfig *main_config) done: if (_Py_INIT_FAILED(err)) { - pathconfig_clear(&new_path_config); + _PyPathConfig_Clear(&new_path_config); } calculate_free(&calculate); return err; } -static void -pathconfig_global_init(void) -{ - if (_Py_path_config.module_search_path) { - /* Already initialized */ - return; - } - - _PyInitError err; - _PyMainInterpreterConfig config = _PyMainInterpreterConfig_INIT; - - err = _PyMainInterpreterConfig_ReadEnv(&config); - if (_Py_INIT_FAILED(err)) { - goto error; - } - - err = _PyMainInterpreterConfig_Read(&config); - if (_Py_INIT_FAILED(err)) { - goto error; - } - - err = _PyPathConfig_Init(&config); - if (_Py_INIT_FAILED(err)) { - goto error; - } - - _PyMainInterpreterConfig_Clear(&config); - return; - -error: - _PyMainInterpreterConfig_Clear(&config); - _Py_FatalInitError(err); -} - - -void -_PyPathConfig_Fini(void) -{ - pathconfig_clear(&_Py_path_config); -} - - -/* External interface */ - -void -Py_SetPath(const wchar_t *path) -{ - if (_Py_path_config.module_search_path != NULL) { - pathconfig_clear(&_Py_path_config); - } - - if (path == NULL) { - return; - } - - _PyPathConfig new_config; - new_config.program_full_path = _PyMem_RawWcsdup(Py_GetProgramName()); - new_config.prefix = _PyMem_RawWcsdup(L""); - new_config.dll_path = _PyMem_RawWcsdup(L""); - new_config.module_search_path = _PyMem_RawWcsdup(path); - - pathconfig_clear(&_Py_path_config); - _Py_path_config = new_config; -} - - -wchar_t * -Py_GetPath(void) -{ - pathconfig_global_init(); - return _Py_path_config.module_search_path; -} - - -wchar_t * -Py_GetPrefix(void) -{ - pathconfig_global_init(); - return _Py_path_config.prefix; -} - - -wchar_t * -Py_GetExecPrefix(void) -{ - return Py_GetPrefix(); -} - - -wchar_t * -Py_GetProgramFullPath(void) -{ - pathconfig_global_init(); - return _Py_path_config.program_full_path; -} - - /* Load python3.dll before loading any extension module that might refer to it. That way, we can be sure that always the python3.dll corresponding to this python DLL is loaded, not a python3.dll that might be on the path diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 3793cbda882..b430e05b629 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -381,6 +381,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 1d33c6e2cc2..c9aa3da355e 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -896,6 +896,9 @@ Python + + Python + Python diff --git a/Python/pathconfig.c b/Python/pathconfig.c new file mode 100644 index 00000000000..daa22270369 --- /dev/null +++ b/Python/pathconfig.c @@ -0,0 +1,189 @@ +/* Path configuration like module_search_path (sys.path) */ + +#include "Python.h" +#include "osdefs.h" +#include "internal/pystate.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +_PyPathConfig _Py_path_config = _PyPathConfig_INIT; +#ifdef MS_WINDOWS +static wchar_t *progname = L"python"; +#else +static wchar_t *progname = L"python3"; +#endif +static wchar_t *default_home = NULL; + + +void +_PyPathConfig_Clear(_PyPathConfig *config) +{ +#define CLEAR(ATTR) \ + do { \ + PyMem_RawFree(ATTR); \ + ATTR = NULL; \ + } while (0) + + CLEAR(config->prefix); + CLEAR(config->program_full_path); +#ifdef MS_WINDOWS + CLEAR(config->dll_path); +#else + CLEAR(config->exec_prefix); +#endif + CLEAR(config->module_search_path); +#undef CLEAR +} + + +void +Py_SetProgramName(wchar_t *pn) +{ + if (pn && *pn) + progname = pn; +} + + +wchar_t * +Py_GetProgramName(void) +{ + return progname; +} + + +void +Py_SetPythonHome(wchar_t *home) +{ + default_home = home; +} + + +wchar_t* +Py_GetPythonHome(void) +{ + /* Use a static buffer to avoid heap memory allocation failure. + Py_GetPythonHome() doesn't allow to report error, and the caller + doesn't release memory. */ + static wchar_t buffer[MAXPATHLEN+1]; + + if (default_home) { + return default_home; + } + + char *home = Py_GETENV("PYTHONHOME"); + if (!home) { + return NULL; + } + + size_t size = Py_ARRAY_LENGTH(buffer); + size_t r = mbstowcs(buffer, home, size); + if (r == (size_t)-1 || r >= size) { + /* conversion failed or the static buffer is too small */ + return NULL; + } + + return buffer; +} + + +static void +pathconfig_global_init(void) +{ + if (_Py_path_config.module_search_path) { + /* Already initialized */ + return; + } + + _PyInitError err; + _PyMainInterpreterConfig config = _PyMainInterpreterConfig_INIT; + + err = _PyMainInterpreterConfig_ReadEnv(&config); + if (_Py_INIT_FAILED(err)) { + goto error; + } + + err = _PyMainInterpreterConfig_Read(&config); + if (_Py_INIT_FAILED(err)) { + goto error; + } + + err = _PyPathConfig_Init(&config); + if (_Py_INIT_FAILED(err)) { + goto error; + } + + _PyMainInterpreterConfig_Clear(&config); + return; + +error: + _PyMainInterpreterConfig_Clear(&config); + _Py_FatalInitError(err); +} + + +/* External interface */ + +void +Py_SetPath(const wchar_t *path) +{ + if (path == NULL) { + _PyPathConfig_Clear(&_Py_path_config); + return; + } + + _PyPathConfig new_config; + new_config.program_full_path = _PyMem_RawWcsdup(Py_GetProgramName()); + new_config.prefix = _PyMem_RawWcsdup(L""); +#ifdef MS_WINDOWS + new_config.dll_path = _PyMem_RawWcsdup(L""); +#else + new_config.exec_prefix = _PyMem_RawWcsdup(L""); +#endif + new_config.module_search_path = _PyMem_RawWcsdup(path); + + _PyPathConfig_Clear(&_Py_path_config); + _Py_path_config = new_config; +} + + +wchar_t * +Py_GetPath(void) +{ + pathconfig_global_init(); + return _Py_path_config.module_search_path; +} + + +wchar_t * +Py_GetPrefix(void) +{ + pathconfig_global_init(); + return _Py_path_config.prefix; +} + + +wchar_t * +Py_GetExecPrefix(void) +{ +#ifdef MS_WINDOWS + return Py_GetPrefix(); +#else + pathconfig_global_init(); + return _Py_path_config.exec_prefix; +#endif +} + + +wchar_t * +Py_GetProgramFullPath(void) +{ + pathconfig_global_init(); + return _Py_path_config.program_full_path; +} + +#ifdef __cplusplus +} +#endif diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index a1b29f2a0eb..8d71154c563 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1489,61 +1489,6 @@ Py_EndInterpreter(PyThreadState *tstate) PyInterpreterState_Delete(interp); } -#ifdef MS_WINDOWS -static wchar_t *progname = L"python"; -#else -static wchar_t *progname = L"python3"; -#endif - -void -Py_SetProgramName(wchar_t *pn) -{ - if (pn && *pn) - progname = pn; -} - -wchar_t * -Py_GetProgramName(void) -{ - return progname; -} - -static wchar_t *default_home = NULL; - -void -Py_SetPythonHome(wchar_t *home) -{ - default_home = home; -} - - -wchar_t* -Py_GetPythonHome(void) -{ - /* Use a static buffer to avoid heap memory allocation failure. - Py_GetPythonHome() doesn't allow to report error, and the caller - doesn't release memory. */ - static wchar_t buffer[MAXPATHLEN+1]; - - if (default_home) { - return default_home; - } - - char *home = Py_GETENV("PYTHONHOME"); - if (!home) { - return NULL; - } - - size_t size = Py_ARRAY_LENGTH(buffer); - size_t r = mbstowcs(buffer, home, size); - if (r == (size_t)-1 || r >= size) { - /* conversion failed or the static buffer is too small */ - return NULL; - } - - return buffer; -} - /* Add the __main__ module */ static _PyInitError