[gdb/python] Factor out and refactor py_initialize

Function do_start_initialization has a large part dedicated to initializing
the python interpreter, as opposed to the rest of the function where
gdb-specific python support is initialized.

Factor out this part, as new function py_initialize, and rename the existing
py_initialize to py_initialize_catch_abort.

Refactor the new function py_initialize by getting rid of the nested:
...
 #ifdef WITH_PYTHON_PATH
 #if PY_VERSION_HEX < 0x030a0000
 #else
 #endif
 #else
 #endif
...

In particular, this changes behaviour for the "!defined (WITH_PYTHON_PATH)"
case.

For the "defined (WITH_PYTHON_PATH)" case, we've started using
Py_InitializeFromConfig () for PY_VERSION_HEX >= 0x030a0000 to deal with the
deprecation of Py_SetProgramName in 3.11.

For the "!defined (WITH_PYTHON_PATH)" case, we don't use Py_SetProgramName so
we stuck with Py_Initialize ().

However, in 3.12 Py_DontWriteBytecodeFlag and Py_IgnoreEnvironmentFlag got
deprecated and also here we need Py_InitializeFromConfig () to deal with this,
but the "!defined (WITH_PYTHON_PATH)" case didn't get updated.

This should be taken care of, now that we have this behavior:
- for PY_VERSION_HEX < 0x030a0000 we use Py_Initialize
- for PY_VERSION_HEX >= 0x030a0000 we use Py_InitializeFromConfig

I'm not sure how to test the "!defined (WITH_PYTHON_PATH)" though.

Tested on aarch64-linux.

Approved-By: Tom Tromey <tom@tromey.com>
This commit is contained in:
Tom de Vries
2024-12-03 22:49:40 +01:00
parent 22a7a2d12a
commit 125f702105

View File

@@ -2318,7 +2318,7 @@ static bool py_isinitialized = false;
/* Call Py_Initialize (), and return true if successful. */
static bool ATTRIBUTE_UNUSED
py_initialize ()
py_initialize_catch_abort ()
{
auto prev_handler = signal (SIGABRT, catch_python_fatal);
SCOPE_EXIT { signal (SIGABRT, prev_handler); };
@@ -2336,20 +2336,25 @@ py_initialize ()
return py_isinitialized;
}
static bool
do_start_initialization ()
{
/* Define all internal modules. These are all imported (and thus
created) during initialization. */
struct _inittab mods[] =
{
{ "_gdb", init__gdb_module },
{ "_gdbevents", gdbpy_events_mod_func },
{ nullptr, nullptr }
};
/* Initialize python, either by calling Py_Initialize or
Py_InitializeFromConfig, and return true if successful. */
if (PyImport_ExtendInittab (mods) < 0)
return false;
static bool
py_initialize ()
{
#if PY_VERSION_HEX < 0x030a0000
/* Python documentation indicates that the memory given
to Py_SetProgramName cannot be freed. However, it seems that
at least Python 3.7.4 Py_SetProgramName takes a copy of the
given program_name. Making progname_copy static and not release
the memory avoids a leak report for Python versions that duplicate
program_name, and respect the requirement of Py_SetProgramName
for Python versions that do not duplicate program_name. */
static wchar_t *progname_copy = nullptr;
#else
wchar_t *progname_copy = nullptr;
SCOPE_EXIT { XDELETEVEC (progname_copy); };
#endif
#ifdef WITH_PYTHON_PATH
/* Work around problem where python gets confused about where it is,
@@ -2361,14 +2366,6 @@ do_start_initialization ()
gdb::unique_xmalloc_ptr<char> progname
(concat (ldirname (python_libdir.c_str ()).c_str (), SLASH_STRING, "bin",
SLASH_STRING, "python", (char *) NULL));
/* Python documentation indicates that the memory given
to Py_SetProgramName cannot be freed. However, it seems that
at least Python 3.7.4 Py_SetProgramName takes a copy of the
given program_name. Making progname_copy static and not release
the memory avoids a leak report for Python versions that duplicate
program_name, and respect the requirement of Py_SetProgramName
for Python versions that do not duplicate program_name. */
static wchar_t *progname_copy;
{
std::string oldloc = setlocale (LC_ALL, NULL);
@@ -2384,6 +2381,7 @@ do_start_initialization ()
return false;
}
}
#endif
/* Py_SetProgramName was deprecated in Python 3.11. Use PyConfig
mechanisms for Python 3.10 and newer. */
@@ -2391,17 +2389,21 @@ do_start_initialization ()
/* Note that Py_SetProgramName expects the string it is passed to
remain alive for the duration of the program's execution, so
it is not freed after this call. */
Py_SetProgramName (progname_copy);
if (!py_initialize ())
return false;
if (progname_copy != nullptr)
Py_SetProgramName (progname_copy);
return py_initialize_catch_abort ();
#else
PyConfig config;
PyConfig_InitPythonConfig (&config);
PyStatus status = PyConfig_SetString (&config, &config.program_name,
progname_copy);
if (PyStatus_Exception (status))
goto init_done;
PyStatus status;
if (progname_copy != nullptr)
{
status = PyConfig_SetString (&config, &config.program_name,
progname_copy);
if (PyStatus_Exception (status))
goto init_done;
}
config.write_bytecode = python_write_bytecode ();
config.use_environment = !python_ignore_environment;
@@ -2423,12 +2425,29 @@ init_done:
status.exitcode);
return false;
}
py_isinitialized = true;
return true;
#endif
#else
}
static bool
do_start_initialization ()
{
/* Define all internal modules. These are all imported (and thus
created) during initialization. */
struct _inittab mods[] =
{
{ "_gdb", init__gdb_module },
{ "_gdbevents", gdbpy_events_mod_func },
{ nullptr, nullptr }
};
if (PyImport_ExtendInittab (mods) < 0)
return false;
if (!py_initialize ())
return false;
#endif
#if PY_VERSION_HEX < 0x03090000
/* PyEval_InitThreads became deprecated in Python 3.9 and will