Skip to content

Commit fe587fc

Browse files
committed
Handle Python 3.11 deprecation of PySys_SetPath and Py_SetProgramName
Python 3.11 deprecates PySys_SetPath and Py_SetProgramName. The PyConfig API replaces these and other functions. This commit uses the PyConfig API to provide equivalent functionality while also preserving support for older versions of Python, i.e. those before Python 3.8. A beta version of Python 3.11 is available in Fedora Rawhide. Both Fedora 35 and Fedora 36 use Python 3.10, while Fedora 34 still used Python 3.9. I've tested these changes on Fedora 34, Fedora 36, and rawhide, though complete testing was not possible on rawhide due to a kernel bug. That being the case, I decided to enable the newer PyConfig API by testing PY_VERSION_HEX against 0x030a0000. This corresponds to Python 3.10. We could try to use the PyConfig API for Python versions as early as 3.8, but I'm reluctant to do this as there may have been PyConfig related bugs in earlier versions which have since been fixed. Recent linux distributions should have support for Python 3.10. This should be more than adequate for testing the new Python initialization code in GDB. Information about the PyConfig API as well as the motivation behind deprecating the old interface can be found at these links: python/cpython#88279 https://peps.python.org/pep-0587/ https://docs.python.org/3.11/c-api/init_config.html The v2 commit also addresses several problems that Simon found in the v1 version. In v1, I had used Py_DontWriteBytecodeFlag in the new initialization code, but Simon pointed out that this global configuration variable will be deprecated in Python 3.12. This version of the patch no longer uses Py_DontWriteBytecodeFlag in the new initialization code. Additionally, both Py_DontWriteBytecodeFlag and Py_IgnoreEnvironmentFlag will no longer be used when building GDB against Python 3.10 or higher. While it's true that both of these global configuration variables are deprecated in Python 3.12, it makes sense to disable their use for gdb builds against 3.10 and higher since those are the versions for which the PyConfig API is now being used by GDB. (The PyConfig API includes different mechanisms for making the same settings afforded by use of the soon-to-be deprecated global configuration variables.) Simon also noted that PyConfig_Clear() would not have be called for one of the failure paths. I've fixed that problem and also made the rest of the "bail out" code more direct. In particular, PyConfig_Clear() will always be called, both for success and failure. The v3 patch addresses some rebase conflicts related to module initialization . Commit 3acd9a6 ("Make 'import gdb.events' work") uses PyImport_ExtendInittab instead of PyImport_AppendInittab. That commit also initializes a struct for each module to import. Both the initialization and the call to were moved ahead of the ifdefs to avoid having to replicate (at least some of) the code three times in various portions of the ifdefs. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28668 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=29287
1 parent b0cf0a5 commit fe587fc

File tree

2 files changed

+86
-18
lines changed

2 files changed

+86
-18
lines changed

gdb/python/python-internal.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ gdb_PySys_GetObject (const char *name)
177177

178178
#define PySys_GetObject gdb_PySys_GetObject
179179

180+
/* PySys_SetPath was deprecated in Python 3.11. Disable the deprecated
181+
code for Python 3.10 and newer. */
182+
#if PY_VERSION_HEX < 0x030a0000
183+
180184
/* PySys_SetPath's 'path' parameter was missing the 'const' qualifier
181185
before Python 3.6. Hence, we wrap it in a function to avoid errors
182186
when compiled with -Werror. */
@@ -190,6 +194,7 @@ gdb_PySys_SetPath (const GDB_PYSYS_SETPATH_CHAR *path)
190194
}
191195

192196
#define PySys_SetPath gdb_PySys_SetPath
197+
#endif
193198

194199
/* Wrap PyGetSetDef to allow convenient construction with string
195200
literals. Unfortunately, PyGetSetDef's 'name' and 'doc' members

gdb/python/python.c

Lines changed: 81 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1820,8 +1820,14 @@ set_python_ignore_environment (const char *args, int from_tty,
18201820
struct cmd_list_element *c)
18211821
{
18221822
#ifdef HAVE_PYTHON
1823+
/* Py_IgnoreEnvironmentFlag is deprecated in Python 3.12. Disable
1824+
its usage in Python 3.10 and above since the PyConfig mechanism
1825+
is now (also) used in 3.10 and higher. See do_start_initialization()
1826+
in this file. */
1827+
#if PY_VERSION_HEX < 0x030a0000
18231828
Py_IgnoreEnvironmentFlag = python_ignore_environment ? 1 : 0;
18241829
#endif
1830+
#endif
18251831
}
18261832

18271833
/* When this is turned on before Python is initialised then Python will
@@ -1849,6 +1855,24 @@ show_python_dont_write_bytecode (struct ui_file *file, int from_tty,
18491855
value);
18501856
}
18511857

1858+
/* Return value to assign to PyConfig.write_bytecode or, when
1859+
negated (via !), Py_DontWriteBytecodeFlag. Py_DontWriteBytecodeFlag
1860+
is deprecated in Python 3.12. */
1861+
1862+
static int
1863+
python_write_bytecode ()
1864+
{
1865+
int wbc = 0;
1866+
1867+
if (python_dont_write_bytecode == AUTO_BOOLEAN_AUTO)
1868+
wbc = (!python_ignore_environment
1869+
&& getenv ("PYTHONDONTWRITEBYTECODE") != nullptr) ? 0 : 1;
1870+
else
1871+
wbc = python_dont_write_bytecode == AUTO_BOOLEAN_TRUE ? 0 : 1;
1872+
1873+
return wbc;
1874+
}
1875+
18521876
/* Implement 'set python dont-write-bytecode'. This sets Python's internal
18531877
flag no matter when the command is issued, however, if this is used
18541878
after Py_Initialize has been called then many modules could already
@@ -1859,13 +1883,13 @@ set_python_dont_write_bytecode (const char *args, int from_tty,
18591883
struct cmd_list_element *c)
18601884
{
18611885
#ifdef HAVE_PYTHON
1862-
if (python_dont_write_bytecode == AUTO_BOOLEAN_AUTO)
1863-
Py_DontWriteBytecodeFlag
1864-
= (!python_ignore_environment
1865-
&& getenv ("PYTHONDONTWRITEBYTECODE") != nullptr) ? 1 : 0;
1866-
else
1867-
Py_DontWriteBytecodeFlag
1868-
= python_dont_write_bytecode == AUTO_BOOLEAN_TRUE ? 1 : 0;
1886+
/* Py_DontWriteBytecodeFlag is deprecated in Python 3.12. Disable
1887+
its usage in Python 3.10 and above since the PyConfig mechanism
1888+
is now (also) used in 3.10 and higher. See do_start_initialization()
1889+
in this file. */
1890+
#if PY_VERSION_HEX < 0x030a0000
1891+
Py_DontWriteBytecodeFlag = !python_write_bytecode ();
1892+
#endif
18691893
#endif /* HAVE_PYTHON */
18701894
}
18711895

@@ -1970,6 +1994,18 @@ gdbpy_gdb_exiting (int exit_code)
19701994
static bool
19711995
do_start_initialization ()
19721996
{
1997+
/* Define all internal modules. These are all imported (and thus
1998+
created) during initialization. */
1999+
struct _inittab mods[] =
2000+
{
2001+
{ "_gdb", init__gdb_module },
2002+
{ "_gdbevents", gdbpy_events_mod_func },
2003+
{ nullptr, nullptr }
2004+
};
2005+
2006+
if (PyImport_ExtendInittab (mods) < 0)
2007+
return false;
2008+
19732009
#ifdef WITH_PYTHON_PATH
19742010
/* Work around problem where python gets confused about where it is,
19752011
and then can't find its libraries, etc.
@@ -2001,25 +2037,41 @@ do_start_initialization ()
20012037
}
20022038
setlocale (LC_ALL, oldloc.c_str ());
20032039

2040+
/* Py_SetProgramName was deprecated in Python 3.11. Use PyConfig
2041+
mechanisms for Python 3.10 and newer. */
2042+
#if PY_VERSION_HEX < 0x030a0000
20042043
/* Note that Py_SetProgramName expects the string it is passed to
20052044
remain alive for the duration of the program's execution, so
20062045
it is not freed after this call. */
20072046
Py_SetProgramName (progname_copy);
2008-
#endif
2047+
Py_Initialize ();
2048+
#else
2049+
PyConfig config;
20092050

2010-
/* Define all internal modules. These are all imported (and thus
2011-
created) during initialization. */
2012-
struct _inittab mods[3] =
2013-
{
2014-
{ "_gdb", init__gdb_module },
2015-
{ "_gdbevents", gdbpy_events_mod_func },
2016-
{ nullptr, nullptr }
2017-
};
2051+
PyConfig_InitPythonConfig (&config);
2052+
PyStatus status = PyConfig_SetString (&config, &config.program_name,
2053+
progname_copy);
2054+
if (PyStatus_Exception (status))
2055+
goto init_done;
20182056

2019-
if (PyImport_ExtendInittab (mods) < 0)
2020-
return false;
2057+
config.write_bytecode = python_write_bytecode ();
2058+
config.use_environment = !python_ignore_environment;
20212059

2060+
status = PyConfig_Read (&config);
2061+
if (PyStatus_Exception (status))
2062+
goto init_done;
2063+
2064+
status = Py_InitializeFromConfig (&config);
2065+
2066+
init_done:
2067+
PyConfig_Clear (&config);
2068+
if (PyStatus_Exception (status))
2069+
return false;
2070+
#endif
2071+
#else
20222072
Py_Initialize ();
2073+
#endif
2074+
20232075
#if PY_VERSION_HEX < 0x03090000
20242076
/* PyEval_InitThreads became deprecated in Python 3.9 and will
20252077
be removed in Python 3.11. Prior to Python 3.7, this call was
@@ -2325,12 +2377,23 @@ do_initialize (const struct extension_language_defn *extlang)
23252377

23262378
sys_path = PySys_GetObject ("path");
23272379

2380+
/* PySys_SetPath was deprecated in Python 3.11. Disable this
2381+
deprecated code for Python 3.10 and newer. Also note that this
2382+
ifdef eliminates potential initialization of sys.path via
2383+
PySys_SetPath. My (kevinb's) understanding of PEP 587 suggests
2384+
that it's not necessary due to module_search_paths being
2385+
initialized to an empty list following any of the PyConfig
2386+
initialization functions. If it does turn out that some kind of
2387+
initialization is still needed, it should be added to the
2388+
PyConfig-based initialization in do_start_initialize(). */
2389+
#if PY_VERSION_HEX < 0x030a0000
23282390
/* If sys.path is not defined yet, define it first. */
23292391
if (!(sys_path && PyList_Check (sys_path)))
23302392
{
23312393
PySys_SetPath (L"");
23322394
sys_path = PySys_GetObject ("path");
23332395
}
2396+
#endif
23342397
if (sys_path && PyList_Check (sys_path))
23352398
{
23362399
gdbpy_ref<> pythondir (PyUnicode_FromString (gdb_pythondir.c_str ()));

0 commit comments

Comments
 (0)