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
This commit is contained in:
Victor Stinner 2017-12-01 20:50:58 +01:00 committed by GitHub
parent ebac19dad6
commit 0ea395ae96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 204 additions and 291 deletions

View File

@ -52,6 +52,10 @@ typedef struct {
#define _PyPathConfig_INIT {.module_search_path = NULL} #define _PyPathConfig_INIT {.module_search_path = NULL}
PyAPI_DATA(_PyPathConfig) _Py_path_config;
PyAPI_FUNC(void) _PyPathConfig_Clear(_PyPathConfig *config);
/* Full Python runtime state */ /* Full Python runtime state */

View File

@ -105,7 +105,6 @@ PyAPI_FUNC(wchar_t *) Py_GetPath(void);
#ifdef Py_BUILD_CORE #ifdef Py_BUILD_CORE
PyAPI_FUNC(_PyInitError) _PyPathConfig_Init( PyAPI_FUNC(_PyInitError) _PyPathConfig_Init(
const _PyMainInterpreterConfig *main_config); const _PyMainInterpreterConfig *main_config);
PyAPI_FUNC(void) _PyPathConfig_Fini(void);
#endif #endif
PyAPI_FUNC(void) Py_SetPath(const wchar_t *); PyAPI_FUNC(void) Py_SetPath(const wchar_t *);
#ifdef MS_WINDOWS #ifdef MS_WINDOWS

View File

@ -337,8 +337,9 @@ PYTHON_OBJS= \
Python/importdl.o \ Python/importdl.o \
Python/marshal.o \ Python/marshal.o \
Python/modsupport.o \ Python/modsupport.o \
Python/mystrtoul.o \
Python/mysnprintf.o \ Python/mysnprintf.o \
Python/mystrtoul.o \
Python/pathconfig.o \
Python/peephole.o \ Python/peephole.o \
Python/pyarena.o \ Python/pyarena.o \
Python/pyctype.o \ Python/pyctype.o \

View File

@ -132,7 +132,6 @@ typedef struct {
static const wchar_t delimiter[2] = {DELIM, '\0'}; static const wchar_t delimiter[2] = {DELIM, '\0'};
static const wchar_t separator[2] = {SEP, '\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. */ /* 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() /* Initialize paths for Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix()
and Py_GetProgramFullPath() */ and Py_GetProgramFullPath() */
_PyInitError _PyInitError
@ -1049,7 +1031,7 @@ _PyPathConfig_Init(const _PyMainInterpreterConfig *main_config)
err = calculate_path_impl(main_config, &calculate, &new_path_config); err = calculate_path_impl(main_config, &calculate, &new_path_config);
if (_Py_INIT_FAILED(err)) { if (_Py_INIT_FAILED(err)) {
pathconfig_clear(&new_path_config); _PyPathConfig_Clear(&new_path_config);
goto done; goto done;
} }
@ -1061,100 +1043,6 @@ done:
return err; 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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -1665,12 +1665,12 @@ pymain_impl(_PyMain *pymain)
pymain->status = 120; 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 Py_Initialize() and Py_Finalize() can be called multiple times, but it
must not "forget" parameters set by Py_SetProgramName(), Py_SetPath() or 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. */ parameters. */
_PyPathConfig_Fini(); _PyPathConfig_Clear(&_Py_path_config);
return 0; return 0;
} }

View File

@ -130,9 +130,6 @@ typedef struct {
} PyCalculatePath; } PyCalculatePath;
static _PyPathConfig _Py_path_config = _PyPathConfig_INIT;
/* determine if "ch" is a separator character */ /* determine if "ch" is a separator character */
static int static int
is_sep(wchar_t ch) 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() /* Initialize paths for Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix()
and Py_GetProgramFullPath() */ and Py_GetProgramFullPath() */
_PyInitError _PyInitError
@ -1108,110 +1088,13 @@ _PyPathConfig_Init(const _PyMainInterpreterConfig *main_config)
done: done:
if (_Py_INIT_FAILED(err)) { if (_Py_INIT_FAILED(err)) {
pathconfig_clear(&new_path_config); _PyPathConfig_Clear(&new_path_config);
} }
calculate_free(&calculate); calculate_free(&calculate);
return err; 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 /* 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 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 to this python DLL is loaded, not a python3.dll that might be on the path

View File

@ -381,6 +381,7 @@
<ClCompile Include="..\Python\modsupport.c" /> <ClCompile Include="..\Python\modsupport.c" />
<ClCompile Include="..\Python\mysnprintf.c" /> <ClCompile Include="..\Python\mysnprintf.c" />
<ClCompile Include="..\Python\mystrtoul.c" /> <ClCompile Include="..\Python\mystrtoul.c" />
<ClCompile Include="..\Python\pathconfig.c" />
<ClCompile Include="..\Python\peephole.c" /> <ClCompile Include="..\Python\peephole.c" />
<ClCompile Include="..\Python\pyarena.c" /> <ClCompile Include="..\Python\pyarena.c" />
<ClCompile Include="..\Python\pyctype.c" /> <ClCompile Include="..\Python\pyctype.c" />

View File

@ -896,6 +896,9 @@
<ClCompile Include="..\Python\mystrtoul.c"> <ClCompile Include="..\Python\mystrtoul.c">
<Filter>Python</Filter> <Filter>Python</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\Python\pathconfig.c">
<Filter>Python</Filter>
</ClCompile>
<ClCompile Include="..\Python\peephole.c"> <ClCompile Include="..\Python\peephole.c">
<Filter>Python</Filter> <Filter>Python</Filter>
</ClCompile> </ClCompile>

189
Python/pathconfig.c Normal file
View File

@ -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

View File

@ -1489,61 +1489,6 @@ Py_EndInterpreter(PyThreadState *tstate)
PyInterpreterState_Delete(interp); 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 */ /* Add the __main__ module */
static _PyInitError static _PyInitError