Skip to content

Commit

Permalink
Add free-threaded Python support (#2310)
Browse files Browse the repository at this point in the history
Co-authored-by: Nathan Goldbaum <[email protected]>
  • Loading branch information
messense and ngoldbaum authored Nov 25, 2024
1 parent ceaefd5 commit 65404af
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 55 deletions.
16 changes: 10 additions & 6 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number }}
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.action }}-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
Expand Down Expand Up @@ -43,9 +43,10 @@ jobs:
- macos-14
- windows-latest
python-version:
- '3.9'
- '3.13'
- 'pypy3.10'
- "3.9"
- "3.13"
- "3.13t"
- "pypy3.10"
exclude:
# Skip PyPy on macOS M1 runner because they are built for x86_64
- os: macos-14
Expand Down Expand Up @@ -81,7 +82,7 @@ jobs:
auto-activate-base: "false"
activate-environment: ""
miniconda-version: "latest"
- uses: actions/setup-python@v5
- uses: Quansight-Labs/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Set PYTHON_VERSION env var
Expand All @@ -96,7 +97,10 @@ jobs:
run: |
uv tool install virtualenv
uv tool install twine
uv pip install --system "ziglang>=0.10.0,<0.13.0" uniffi-bindgen==0.28.0
uv tool install uniffi-bindgen==0.28.0
- uses: mlugg/setup-zig@v1
with:
version: 0.12.1
- uses: dtolnay/rust-toolchain@stable
id: rustup
with:
Expand Down
2 changes: 1 addition & 1 deletion src/auditwheel/audit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::{fmt, io};
use thiserror::Error;

static IS_LIBPYTHON: Lazy<Regex> =
Lazy::new(|| Regex::new(r"^libpython3\.\d+m?u?\.so\.\d+\.\d+$").unwrap());
Lazy::new(|| Regex::new(r"^libpython3\.\d+m?u?t?\.so\.\d+\.\d+$").unwrap());

/// Error raised during auditing an elf file for manylinux/musllinux compatibility
#[derive(Error, Debug)]
Expand Down
38 changes: 30 additions & 8 deletions src/build_options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,10 @@ impl BuildOptions {
.get("ABIFLAGS")
.map(ToString::to_string)
.unwrap_or_default();
let gil_disabled = sysconfig_data
.get("Py_GIL_DISABLED")
.map(|x| x == "1")
.unwrap_or_default();
let ext_suffix = sysconfig_data
.get("EXT_SUFFIX")
.context("syconfig didn't define an `EXT_SUFFIX` ಠ_ಠ")?;
Expand All @@ -299,6 +303,7 @@ impl BuildOptions {
abiflags,
ext_suffix: ext_suffix.to_string(),
pointer_width: None,
gil_disabled,
},
executable: PathBuf::new(),
platform: None,
Expand Down Expand Up @@ -376,6 +381,7 @@ impl BuildOptions {
abiflags: "".to_string(),
ext_suffix: ".pyd".to_string(),
pointer_width: None,
gil_disabled: false,
},
executable: PathBuf::new(),
platform: None,
Expand All @@ -402,6 +408,7 @@ impl BuildOptions {
abiflags: "".to_string(),
ext_suffix: ".pyd".to_string(),
pointer_width: None,
gil_disabled: false,
},
executable: PathBuf::new(),
platform: None,
Expand Down Expand Up @@ -441,6 +448,7 @@ impl BuildOptions {
abiflags: "".to_string(),
ext_suffix: "".to_string(),
pointer_width: None,
gil_disabled: false,
},
executable: PathBuf::new(),
platform: None,
Expand Down Expand Up @@ -1244,26 +1252,35 @@ fn find_interpreter_in_sysconfig(
let mut interpreters = Vec::new();
for interp in interpreter {
let python = interp.display().to_string();
let (python_impl, python_ver) = if let Some(ver) = python.strip_prefix("pypy") {
(InterpreterKind::PyPy, ver.strip_prefix('-').unwrap_or(ver))
} else if let Some(ver) = python.strip_prefix("graalpy") {
let (python_impl, python_ver, abiflags) = if let Some(ver) = python.strip_prefix("pypy") {
(
InterpreterKind::GraalPy,
InterpreterKind::PyPy,
ver.strip_prefix('-').unwrap_or(ver),
"",
)
} else if let Some(ver) = python.strip_prefix("python") {
} else if let Some(ver) = python.strip_prefix("graalpy") {
(
InterpreterKind::CPython,
InterpreterKind::GraalPy,
ver.strip_prefix('-').unwrap_or(ver),
"",
)
} else if let Some(ver) = python.strip_prefix("python") {
// Also accept things like `python3.13t` for free-threaded python
let (ver, abiflags) =
if let Some(ver) = ver.strip_prefix('-').unwrap_or(ver).strip_suffix('t') {
(ver, "t")
} else {
(ver, "")
};
(InterpreterKind::CPython, ver, abiflags)
} else if python
.chars()
.next()
.map(|c| c.is_ascii_digit())
.unwrap_or(false)
{
// Eg: -i 3.9 without interpreter kind, assume it's CPython
(InterpreterKind::CPython, &*python)
(InterpreterKind::CPython, &*python, "")
} else {
// if interpreter not known
if std::path::Path::new(&python).is_file() {
Expand All @@ -1284,7 +1301,12 @@ fn find_interpreter_in_sysconfig(
let ver_minor = ver_minor.parse::<usize>().with_context(|| {
format!("Invalid python interpreter minor version '{ver_minor}', expect a digit")
})?;
let sysconfig = InterpreterConfig::lookup_one(target, python_impl, (ver_major, ver_minor))

if (ver_major, ver_minor) < (3, 13) && abiflags == "t" {
bail!("Free-threaded Python interpreter is only supported on 3.13 and later.");
}

let sysconfig = InterpreterConfig::lookup_one(target, python_impl, (ver_major, ver_minor), abiflags)
.with_context(|| {
format!("Failed to find a {python_impl} {ver_major}.{ver_minor} interpreter in known sysconfig")
})?;
Expand Down
1 change: 1 addition & 0 deletions src/cross_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ KEYS = [
"ABIFLAGS",
"EXT_SUFFIX",
"SOABI",
"Py_GIL_DISABLED",
]
for key in KEYS:
print(key, build_time_vars.get(key, ""))
Expand Down
Loading

0 comments on commit 65404af

Please sign in to comment.