Skip to content

Commit 4eb8cd2

Browse files
authored
Python 3.12 support (#642)
1 parent 94e6c90 commit 4eb8cd2

13 files changed

+13214
-166
lines changed

.github/workflows/build.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ jobs:
3535
- name: Install Dependencies
3636
run: sudo apt install libunwind-dev
3737
if: runner.os == 'Linux'
38+
- uses: actions/setup-python@v4
39+
with:
40+
python-version: 3.9
3841
- name: Build
3942
run: cargo build --release --verbose --examples
4043
- uses: actions/setup-python@v4
@@ -180,7 +183,7 @@ jobs:
180183
strategy:
181184
fail-fast: false
182185
matrix:
183-
python-version: [3.6.7, 3.6.15, 3.7.1, 3.7.17, 3.8.0, 3.8.18, 3.9.0, 3.9.20, 3.10.0, 3.10.1, 3.10.2, 3.10.3, 3.10.4, 3.10.5, 3.10.6, 3.10.7, 3.10.8, 3.10.9, 3.10.10, 3.10.11, 3.10.12, 3.10.13, 3.10.14, 3.10.15, 3.11.0, 3.11.1, 3.11.2, 3.11.3, 3.11.4, 3.11.5, 3.11.6, 3.11.7, 3.11.8, 3.11.9, 3.11.10]
186+
python-version: [3.6.7, 3.6.15, 3.7.1, 3.7.17, 3.8.0, 3.8.18, 3.9.0, 3.9.20, 3.10.0, 3.10.1, 3.10.2, 3.10.3, 3.10.4, 3.10.5, 3.10.6, 3.10.7, 3.10.8, 3.10.9, 3.10.10, 3.10.11, 3.10.12, 3.10.13, 3.10.14, 3.10.15, 3.11.0, 3.11.1, 3.11.2, 3.11.3, 3.11.4, 3.11.5, 3.11.6, 3.11.7, 3.11.8, 3.11.9, 3.11.10, 3.12.0]
184187
# TODO: also test windows
185188
os: [ubuntu-20.04, macos-13]
186189
# some versions of python can't be tested on GHA with osx because of SIP:
@@ -207,6 +210,8 @@ jobs:
207210
python-version: 3.11.9
208211
- os: macos-13
209212
python-version: 3.11.10
213+
- os: macos-13
214+
python-version: 3.12.0
210215

211216
steps:
212217
- uses: actions/checkout@v2

generate_bindings.py

Lines changed: 53 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ def build_python(cpython_path, version):
1717
print("Compiling python %s from repo at %s" % (version, cpython_path))
1818
install_path = os.path.abspath(os.path.join(cpython_path, version))
1919

20-
ret = os.system(f"""
20+
ret = os.system(
21+
f"""
2122
cd {cpython_path}
2223
git checkout {version}
2324
@@ -27,7 +28,8 @@ def build_python(cpython_path, version):
2728
../configure prefix={install_path}
2829
make
2930
make install
30-
""")
31+
"""
32+
)
3133
if ret:
3234
return ret
3335

@@ -57,8 +59,9 @@ def calculate_pyruntime_offsets(cpython_path, version, configure=False):
5759
size_t interp_head = offsetof(_PyRuntimeState, interpreters.head);
5860
printf("pub static INTERP_HEAD_OFFSET: usize = %i;\n", interp_head);
5961
60-
size_t tstate_current = offsetof(_PyRuntimeState, gilstate.tstate_current);
61-
printf("pub static TSTATE_CURRENT: usize = %i;\n", tstate_current);
62+
// tstate_current has been replaced by a thread-local variable in python 3.12
63+
// size_t tstate_current = offsetof(_PyRuntimeState, gilstate.tstate_current);
64+
// printf("pub static TSTATE_CURRENT: usize = %i;\n", tstate_current);
6265
}
6366
"""
6467

@@ -88,7 +91,7 @@ def calculate_pyruntime_offsets(cpython_path, version, configure=False):
8891
else:
8992
ret = os.system(f"""gcc {source_filename} -I {cpython_path} -I {cpython_path}/Include -o {exe}""")
9093
if ret:
91-
print("Failed to compile""")
94+
print("Failed to compile")
9295
return ret
9396

9497
ret = os.system(exe)
@@ -100,19 +103,22 @@ def calculate_pyruntime_offsets(cpython_path, version, configure=False):
100103
def extract_bindings(cpython_path, version, configure=False):
101104
print("Generating bindings for python %s from repo at %s" % (version, cpython_path))
102105

103-
ret = os.system(f"""
106+
ret = os.system(
107+
f"""
104108
cd {cpython_path}
105109
git checkout {version}
106110
107111
# need to run configure on the current branch to generate pyconfig.h sometimes
108112
{("./configure prefix=" + os.path.abspath(os.path.join(cpython_path, version))) if configure else ""}
109113
110-
cat Include/Python.h > bindgen_input.h
111-
cat Include/frameobject.h >> bindgen_input.h
114+
115+
echo "// autogenerated by generate_bindings.py " > bindgen_input.h
112116
echo '#define Py_BUILD_CORE 1\n' >> bindgen_input.h
113-
cat Include/internal/pycore_pystate.h >> bindgen_input.h
117+
cat Include/Python.h >> bindgen_input.h
118+
echo '#undef HAVE_STD_ATOMIC' >> bindgen_input.h
119+
cat Include/frameobject.h >> bindgen_input.h
114120
cat Include/internal/pycore_interp.h >> bindgen_input.h
115-
cat Include/internal/pycore_frame.h >> bindgen_input.h
121+
cat Include/internal/pycore_dict.h >> bindgen_input.h
116122
117123
bindgen bindgen_input.h -o bindgen_output.rs \
118124
--with-derive-default \
@@ -132,13 +138,12 @@ def extract_bindings(cpython_path, version, configure=False):
132138
--whitelist-type PyFloatObject \
133139
--whitelist-type PyDictObject \
134140
--whitelist-type PyDictKeysObject \
135-
--whitelist-type PyDictKeyEntry \
136-
--whitelist-type PyDictUnicodeEntry \
137141
--whitelist-type PyObject \
138142
--whitelist-type PyTypeObject \
139143
--whitelist-type PyHeapTypeObject \
140144
-- -I . -I ./Include -I ./Include/internal
141-
""")
145+
"""
146+
)
142147
if ret:
143148
return ret
144149

@@ -152,36 +157,40 @@ def extract_bindings(cpython_path, version, configure=False):
152157
o.write("#![allow(clippy::useless_transmute)]\n")
153158
o.write("#![allow(clippy::default_trait_access)]\n")
154159
o.write("#![allow(clippy::cast_lossless)]\n")
155-
o.write("#![allow(clippy::trivially_copy_pass_by_ref)]\n\n")
156-
o.write("#![allow(clippy::upper_case_acronyms)]\n\n")
160+
o.write("#![allow(clippy::trivially_copy_pass_by_ref)]\n")
161+
o.write("#![allow(clippy::upper_case_acronyms)]\n")
162+
o.write("#![allow(clippy::too_many_arguments)]\n\n")
163+
157164
o.write(open(os.path.join(cpython_path, "bindgen_output.rs")).read())
158165

159166

160167
if __name__ == "__main__":
161-
162168
if sys.platform.startswith("win"):
163169
default_cpython_path = os.path.join(os.getenv("userprofile"), "code", "cpython")
164170
else:
165171
default_cpython_path = os.path.join(os.getenv("HOME"), "code", "cpython")
166172

167-
parser = argparse.ArgumentParser(description="runs bindgen on cpython version",
168-
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
169-
parser.add_argument("--cpython", type=str, default=default_cpython_path,
170-
dest="cpython", help="path to cpython repo")
171-
parser.add_argument("--configure",
172-
help="Run configure script prior to generating bindings",
173-
action="store_true")
174-
parser.add_argument("--pyruntime",
175-
help="generate offsets for pyruntime",
176-
action="store_true")
177-
parser.add_argument("--build",
178-
help="Build python for this version",
179-
action="store_true")
180-
parser.add_argument("--all",
181-
help="Build all versions",
182-
action="store_true")
183-
184-
parser.add_argument("versions", type=str, nargs='*', help='versions to extract')
173+
parser = argparse.ArgumentParser(
174+
description="runs bindgen on cpython version",
175+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
176+
)
177+
parser.add_argument(
178+
"--cpython",
179+
type=str,
180+
default=default_cpython_path,
181+
dest="cpython",
182+
help="path to cpython repo",
183+
)
184+
parser.add_argument(
185+
"--configure",
186+
help="Run configure script prior to generating bindings",
187+
action="store_true",
188+
)
189+
parser.add_argument("--pyruntime", help="generate offsets for pyruntime", action="store_true")
190+
parser.add_argument("--build", help="Build python for this version", action="store_true")
191+
parser.add_argument("--all", help="Build all versions", action="store_true")
192+
193+
parser.add_argument("versions", type=str, nargs="*", help="versions to extract")
185194

186195
args = parser.parse_args()
187196

@@ -191,7 +200,16 @@ def extract_bindings(cpython_path, version, configure=False):
191200
sys.exit(1)
192201

193202
if args.all:
194-
versions = ['v3.8.0b4', 'v3.7.0', 'v3.6.6', 'v3.5.5', 'v3.4.8', 'v3.3.7', 'v3.2.6', 'v2.7.15']
203+
versions = [
204+
"v3.8.0b4",
205+
"v3.7.0",
206+
"v3.6.6",
207+
"v3.5.5",
208+
"v3.4.8",
209+
"v3.3.7",
210+
"v3.2.6",
211+
"v2.7.15",
212+
]
195213
else:
196214
versions = args.versions
197215
if not versions:

src/coredump.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::binary_parser::{parse_binary, BinaryInfo};
1515
use crate::config::Config;
1616
use crate::dump::print_trace;
1717
use crate::python_bindings::{
18-
v2_7_15, v3_10_0, v3_11_0, v3_3_7, v3_5_5, v3_6_6, v3_7_0, v3_8_0, v3_9_5,
18+
v2_7_15, v3_10_0, v3_11_0, v3_12_0, v3_3_7, v3_5_5, v3_6_6, v3_7_0, v3_8_0, v3_9_5,
1919
};
2020
use crate::python_data_access::format_variable;
2121
use crate::python_interpreters::InterpreterState;
@@ -303,6 +303,11 @@ impl PythonCoreDump {
303303
minor: 11,
304304
..
305305
} => self._get_stack::<v3_11_0::_is>(config),
306+
Version {
307+
major: 3,
308+
minor: 12,
309+
..
310+
} => self._get_stack::<v3_12_0::_is>(config),
306311
_ => Err(format_err!(
307312
"Unsupported version of Python: {}",
308313
self.version

src/python_bindings/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
pub mod v2_7_15;
22
pub mod v3_10_0;
33
pub mod v3_11_0;
4+
pub mod v3_12_0;
45
pub mod v3_3_7;
56
pub mod v3_5_5;
67
pub mod v3_6_6;
@@ -71,7 +72,7 @@ pub mod pyruntime {
7172
} => 32,
7273
Version {
7374
major: 3,
74-
minor: 11,
75+
minor: 11..=12,
7576
..
7677
} => 40,
7778
_ => 24,

0 commit comments

Comments
 (0)