Prevent building in GIL-less environment (#4327)
* Prevent building in GIL-less environment * Add change log * add "yet" to phrasing * Add testing to build script * add link to issue * Fix formatting issues --------- Co-authored-by: David Hewitt <mail@davidhewitt.dev>
This commit is contained in:
parent
90c4799951
commit
6be80647cb
|
@ -0,0 +1,3 @@
|
|||
This PR lets PyO3 checks `Py_GIL_DISABLED` build flag and prevents `pyo3-ffi` crate building against GIL-less Python,
|
||||
unless
|
||||
explicitly opt using the `UNSAFE_PYO3_BUILD_FREE_THREADED` environment flag.
|
15
noxfile.py
15
noxfile.py
|
@ -9,7 +9,7 @@ import tempfile
|
|||
from functools import lru_cache
|
||||
from glob import glob
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, Dict, Iterator, List, Optional, Tuple
|
||||
from typing import Any, Callable, Dict, Iterable, Iterator, List, Optional, Tuple
|
||||
|
||||
import nox
|
||||
import nox.command
|
||||
|
@ -655,6 +655,14 @@ def test_version_limits(session: nox.Session):
|
|||
config_file.set("PyPy", "3.11")
|
||||
_run_cargo(session, "check", env=env, expect_error=True)
|
||||
|
||||
# Python build with GIL disabled should fail building
|
||||
config_file.set("CPython", "3.13", build_flags=["Py_GIL_DISABLED"])
|
||||
_run_cargo(session, "check", env=env, expect_error=True)
|
||||
|
||||
# Python build with GIL disabled should pass with env flag on
|
||||
env["UNSAFE_PYO3_BUILD_FREE_THREADED"] = "1"
|
||||
_run_cargo(session, "check", env=env)
|
||||
|
||||
|
||||
@nox.session(name="check-feature-powerset", venv_backend="none")
|
||||
def check_feature_powerset(session: nox.Session):
|
||||
|
@ -919,7 +927,9 @@ class _ConfigFile:
|
|||
def __init__(self, config_file) -> None:
|
||||
self._config_file = config_file
|
||||
|
||||
def set(self, implementation: str, version: str) -> None:
|
||||
def set(
|
||||
self, implementation: str, version: str, build_flags: Iterable[str] = ()
|
||||
) -> None:
|
||||
"""Set the contents of this config file to the given implementation and version."""
|
||||
self._config_file.seek(0)
|
||||
self._config_file.truncate(0)
|
||||
|
@ -927,6 +937,7 @@ class _ConfigFile:
|
|||
f"""\
|
||||
implementation={implementation}
|
||||
version={version}
|
||||
build_flags={','.join(build_flags)}
|
||||
suppress_build_script_link_lines=true
|
||||
"""
|
||||
)
|
||||
|
|
|
@ -996,6 +996,7 @@ pub enum BuildFlag {
|
|||
Py_DEBUG,
|
||||
Py_REF_DEBUG,
|
||||
Py_TRACE_REFS,
|
||||
Py_GIL_DISABLED,
|
||||
COUNT_ALLOCS,
|
||||
Other(String),
|
||||
}
|
||||
|
@ -1016,6 +1017,7 @@ impl FromStr for BuildFlag {
|
|||
"Py_DEBUG" => Ok(BuildFlag::Py_DEBUG),
|
||||
"Py_REF_DEBUG" => Ok(BuildFlag::Py_REF_DEBUG),
|
||||
"Py_TRACE_REFS" => Ok(BuildFlag::Py_TRACE_REFS),
|
||||
"Py_GIL_DISABLED" => Ok(BuildFlag::Py_GIL_DISABLED),
|
||||
"COUNT_ALLOCS" => Ok(BuildFlag::COUNT_ALLOCS),
|
||||
other => Ok(BuildFlag::Other(other.to_owned())),
|
||||
}
|
||||
|
@ -1039,10 +1041,11 @@ impl FromStr for BuildFlag {
|
|||
pub struct BuildFlags(pub HashSet<BuildFlag>);
|
||||
|
||||
impl BuildFlags {
|
||||
const ALL: [BuildFlag; 4] = [
|
||||
const ALL: [BuildFlag; 5] = [
|
||||
BuildFlag::Py_DEBUG,
|
||||
BuildFlag::Py_REF_DEBUG,
|
||||
BuildFlag::Py_TRACE_REFS,
|
||||
BuildFlag::Py_GIL_DISABLED,
|
||||
BuildFlag::COUNT_ALLOCS,
|
||||
];
|
||||
|
||||
|
|
|
@ -4,8 +4,9 @@ use pyo3_build_config::{
|
|||
cargo_env_var, env_var, errors::Result, is_linking_libpython, resolve_interpreter_config,
|
||||
InterpreterConfig, PythonVersion,
|
||||
},
|
||||
warn, PythonImplementation,
|
||||
warn, BuildFlag, PythonImplementation,
|
||||
};
|
||||
use std::ops::Not;
|
||||
|
||||
/// Minimum Python version PyO3 supports.
|
||||
struct SupportedVersions {
|
||||
|
@ -120,6 +121,24 @@ fn ensure_python_version(interpreter_config: &InterpreterConfig) -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn ensure_gil_enabled(interpreter_config: &InterpreterConfig) -> Result<()> {
|
||||
let gil_enabled = interpreter_config
|
||||
.build_flags
|
||||
.0
|
||||
.contains(&BuildFlag::Py_GIL_DISABLED)
|
||||
.not();
|
||||
ensure!(
|
||||
gil_enabled || std::env::var("UNSAFE_PYO3_BUILD_FREE_THREADED").map_or(false, |os_str| os_str == "1"),
|
||||
"the Python interpreter was built with the GIL disabled, which is not yet supported by PyO3\n\
|
||||
= help: see https://github.com/PyO3/pyo3/issues/4265 for more information\n\
|
||||
= help: please check if an updated version of PyO3 is available. Current version: {}\n\
|
||||
= help: set UNSAFE_PYO3_BUILD_FREE_THREADED=1 to suppress this check and build anyway for free-threaded Python",
|
||||
std::env::var("CARGO_PKG_VERSION").unwrap()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn ensure_target_pointer_width(interpreter_config: &InterpreterConfig) -> Result<()> {
|
||||
if let Some(pointer_width) = interpreter_config.pointer_width {
|
||||
// Try to check whether the target architecture matches the python library
|
||||
|
@ -185,6 +204,7 @@ fn configure_pyo3() -> Result<()> {
|
|||
|
||||
ensure_python_version(&interpreter_config)?;
|
||||
ensure_target_pointer_width(&interpreter_config)?;
|
||||
ensure_gil_enabled(&interpreter_config)?;
|
||||
|
||||
// Serialize the whole interpreter config into DEP_PYTHON_PYO3_CONFIG env var.
|
||||
interpreter_config.to_cargo_dep_env()?;
|
||||
|
|
Loading…
Reference in New Issue