Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions mingw-w64-python-cryptography/PKGBUILD
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
_realname=cryptography
pkgbase=mingw-w64-python-${_realname}
pkgname=("${MINGW_PACKAGE_PREFIX}-python-${_realname}")
pkgver=48.0.1
pkgver=49.0.0
pkgrel=1
pkgdesc="A package designed to expose cryptographic recipes and primitives to Python developers (mingw-w64)"
arch=('any')
Expand All @@ -29,19 +29,39 @@ makedepends=("${MINGW_PACKAGE_PREFIX}-python-build"
"${MINGW_PACKAGE_PREFIX}-python-maturin"
"${MINGW_PACKAGE_PREFIX}-rust"
"${MINGW_PACKAGE_PREFIX}-cc"
"${MINGW_PACKAGE_PREFIX}-pkgconf")
"${MINGW_PACKAGE_PREFIX}-pkgconf"
"git")
checkdepends=(
#"${MINGW_PACKAGE_PREFIX}-python-iso8601"
"${MINGW_PACKAGE_PREFIX}-python-pretend"
#"${MINGW_PACKAGE_PREFIX}-python-cryptography-vectors"
"${MINGW_PACKAGE_PREFIX}-python-hypothesis"
"${MINGW_PACKAGE_PREFIX}-python-pytz")
source=("https://pypi.org/packages/source/${_realname::1}/${_realname}/${_realname}-${pkgver}.tar.gz")
sha256sums=('266f4ee051abb2f725b74ef8072b521ce1feacf685a3364fa6a6b45548db791a')
source=("https://pypi.org/packages/source/${_realname::1}/${_realname}/${_realname}-${pkgver}.tar.gz"
"git+https://github.com/PyO3/pyo3#tag=v0.29.0"
"pyo3-fix-python-abi-linking.patch")
sha256sums=('f89660a348f4f78a92366240a61404e337586ef7f5909a2fef59ca88ef505493'
'03411beda834ac76b28742d97fc3136bbbcbb4738598fd21633e78301f916e17'
'0b815dcb69127b60bd8250df5f5f4f57e94458240bd634cd2c5c6a4823d7b75b')

prepare() {
cd "${_realname}-${pkgver}"

patch -d ../pyo3 -p1 -i ../pyo3-fix-python-abi-linking.patch
cat >> Cargo.toml <<END

[patch.crates-io]
pyo3.path = "../pyo3"
END

cargo update -p pyo3
}

build() {
cp -r "${_realname}-${pkgver}" "python-build-${MSYSTEM}" && cd "python-build-${MSYSTEM}"

export OPENSSL_NO_VENDOR=1
export PYO3_USE_RAW_DYLIB=0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that you shouldn't need to set this - I think that PyO3 should automatically notice that your lib name isn't in the hardcoded set which support raw-dylib linking and toggle this mode automatically.

(Hopefully in the future the raw-dylib link set shouldn't be hardcoded, this seems to be a limitation in rustc and I'll work to fix it there.)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

without env var it didn't work:(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please retry with latest commit PyO3/pyo3@9451f0e ? I think that should now remove the need for the env var properly (so mingw users do not need to set this for their arbitrary builds)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try later in the evening

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll push these hunks, but it didn't work on my machine

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, thanks. I guess we keep it like this for now in the patch release, I'll work on a better long-term fix upstream.

export _PYTHON_HOST_PLATFORM=$(python -c "import sysconfig, sys; sys.stdout.write(sysconfig.get_platform())")
python -m build --wheel --skip-dependency-check --no-isolation
}
Expand Down
327 changes: 327 additions & 0 deletions mingw-w64-python-cryptography/pyo3-fix-python-abi-linking.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,327 @@
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -236,7 +236,17 @@ unsafe_op_in_unsafe_fn = "warn"
level = "warn"
check-cfg = [
'cfg(pyo3_disable_reference_pool)',
- 'cfg(pyo3_leak_on_drop_without_reference_pool)'
+ 'cfg(pyo3_leak_on_drop_without_reference_pool)',
+ 'cfg(pyo3_use_raw_dylib)',
+ # this horrible hard-coded list should be kept in sync with the list of possible
+ # cfgs in pyo3-ffi/src/impl_/macros.rs
+ #
+ # for library names outside of this set we don't support raw-dylib and require a
+ # proper import library
+ #
+ # maybe in the future this list will not be necessary, see
+ # internals.rust-lang.org/t/support-renames-with-link-name-kind-raw-dylib/24415
+ 'cfg(pyo3_dll, values("python3", "python3_d", "python3t", "python3t_d", "python38", "python38_d", "python39", "python39_d", "python310", "python310_d", "python311", "python311_d", "python312", "python312_d", "python313", "python313_d", "python313t", "python313t_d", "python314", "python314_d", "python314t", "python314t_d", "python315", "python315_d", "python315t", "python315t_d", "python316", "python316_d", "python316t", "python316t_d", "libpypy3.11-c"))',
]


--- a/pyo3-build-config/src/impl_.rs
+++ b/pyo3-build-config/src/impl_.rs
@@ -25,15 +25,6 @@ use crate::{
/// Minimum Python version PyO3 supports.
pub(crate) const MINIMUM_SUPPORTED_VERSION: PythonVersion = PythonVersion { major: 3, minor: 9 };

-pub(crate) const MINIMUM_SUPPORTED_VERSION_PYPY: PythonVersion = PythonVersion {
- major: 3,
- minor: 11,
-};
-pub(crate) const MAXIMUM_SUPPORTED_VERSION_PYPY: PythonVersion = PythonVersion {
- major: 3,
- minor: 11,
-};
-
pub(crate) const MINIMUM_SUPPORTED_VERSION_ABI3T: PythonVersion = PythonVersion {
major: 3,
minor: 15,
@@ -2314,6 +2305,15 @@ fn default_lib_name_for_target(abi: PythonAbi, target: &Triple) -> String {
}

fn default_lib_name_windows(abi: PythonAbi, mingw: bool, debug: bool) -> Result<String> {
+ // mingw formats lib names like unix, and uses a "lib" prefix. We could let the linker
+ // handle "lib" prefix, but that means the `raw-dylib` name is incorrect (where the
+ // "lib" prefix is not automatically added).)
+ if mingw {
+ let mut lib_name = default_lib_name_unix(abi, true, None)?;
+ lib_name.insert_str(0, "lib");
+ return Ok(lib_name);
+ }
+
if abi.implementation.is_pypy() {
// PyPy on Windows ships `libpypy3.X-c.dll` (e.g. `libpypy3.11-c.dll`),
// not CPython's `pythonXY.dll`. With raw-dylib linking we need the real
@@ -2341,13 +2341,6 @@ fn default_lib_name_windows(abi: PythonAbi, mingw: bool, debug: bool) -> Result<
lib_name = lib_name.replace("python3", "python3t");
}
Ok(lib_name)
- } else if mingw {
- ensure!(
- !abi.kind.is_free_threaded(),
- "MinGW free-threaded builds are not currently tested or supported"
- );
- // https://packages.msys2.org/base/mingw-w64-python
- Ok(format!("python{}.{}", abi.version.major, abi.version.minor))
} else if abi.kind().is_free_threaded() {
#[expect(deprecated, reason = "using constant internally")]
{
@@ -2371,28 +2364,36 @@ fn default_lib_name_windows(abi: PythonAbi, mingw: bool, debug: bool) -> Result<
}
}

-fn default_lib_name_unix(abi: PythonAbi, cygwin: bool, ld_version: Option<&str>) -> Result<String> {
+fn default_lib_name_unix(
+ abi: PythonAbi,
+ use_stable_abi_lib: bool,
+ ld_version: Option<&str>,
+) -> Result<String> {
match abi.implementation {
PythonImplementation::CPython => match ld_version {
Some(ld_version) => Ok(format!("python{ld_version}")),
- None => {
- if cygwin && matches!(abi.kind, PythonAbiKind::Stable(StableAbi::Abi3)) {
+ None => match abi.kind {
+ PythonAbiKind::Stable(StableAbi::Abi3) if use_stable_abi_lib => {
Ok("python3".to_string())
- } else if cygwin && matches!(abi.kind, PythonAbiKind::Stable(StableAbi::Abi3t)) {
+ }
+ PythonAbiKind::Stable(StableAbi::Abi3t) if use_stable_abi_lib => {
Ok("python3t".to_string())
- } else if abi.kind.is_free_threaded() {
- #[expect(deprecated, reason = "using constant internally")]
- {
- ensure!(abi.version >= PythonVersion::PY313, "Cannot compile extensions for the free-threaded build on Python versions earlier than 3.13, found {}.{}", abi.version.major, abi.version.minor);
+ }
+ _ => {
+ if abi.kind.is_free_threaded() {
+ #[expect(deprecated, reason = "using constant internally")]
+ {
+ ensure!(abi.version >= PythonVersion::PY313, "Cannot compile extensions for the free-threaded build on Python versions earlier than 3.13, found {}.{}", abi.version.major, abi.version.minor);
+ }
+ Ok(format!(
+ "python{}.{}t",
+ abi.version.major, abi.version.minor
+ ))
+ } else {
+ Ok(format!("python{}.{}", abi.version.major, abi.version.minor))
}
- Ok(format!(
- "python{}.{}t",
- abi.version.major, abi.version.minor
- ))
- } else {
- Ok(format!("python{}.{}", abi.version.major, abi.version.minor))
}
- }
+ },
},
PythonImplementation::PyPy => match ld_version {
Some(ld_version) => Ok(format!("pypy{ld_version}-c")),
--- a/pyo3-build-config/src/lib.rs
+++ b/pyo3-build-config/src/lib.rs
@@ -164,34 +164,6 @@ pub fn print_expected_cfgs() {
for i in impl_::MINIMUM_SUPPORTED_VERSION.minor..=impl_::STABLE_ABI_MAX_MINOR + 1 {
println!("cargo:rustc-check-cfg=cfg(Py_3_{i})");
}
-
- // pyo3_dll cfg for raw-dylib linking on Windows
- let mut dll_names = vec![
- "python3".to_string(),
- "python3_d".to_string(),
- "python3t".to_string(),
- "python3t_d".to_string(),
- ];
- for i in impl_::MINIMUM_SUPPORTED_VERSION.minor..=impl_::STABLE_ABI_MAX_MINOR + 1 {
- dll_names.push(format!("python3{i}"));
- dll_names.push(format!("python3{i}_d"));
- if i >= 13 {
- dll_names.push(format!("python3{i}t"));
- dll_names.push(format!("python3{i}t_d"));
- }
- }
- // PyPy DLL names (libpypy3.X-c.dll)
- for i in
- impl_::MINIMUM_SUPPORTED_VERSION_PYPY.minor..=impl_::MAXIMUM_SUPPORTED_VERSION_PYPY.minor
- {
- dll_names.push(format!("libpypy3.{i}-c"));
- }
- let values = dll_names
- .iter()
- .map(|n| format!("\"{n}\""))
- .collect::<Vec<_>>()
- .join(", ");
- println!("cargo:rustc-check-cfg=cfg(pyo3_dll, values({values}))");
}

/// Private exports used in PyO3's build.rs
--- a/pyo3-ffi/build.rs
+++ b/pyo3-ffi/build.rs
@@ -191,15 +191,79 @@ fn ensure_target_pointer_width(interpreter_config: &InterpreterConfig) -> Result
Ok(())
}

+/// `raw-dylib` currently does not support arbitrary names
+/// (see https://internals.rust-lang.org/t/support-renames-with-link-name-kind-raw-dylib/24415)
+/// so if the lib name is not one of the known subset, we must fall back to full linking.
+fn lib_name_is_known_for_raw_dylib(lib_name: &str) -> bool {
+ // pyo3_dll cfg for raw-dylib linking on Windows
+ if matches!(
+ lib_name,
+ "python3" | "python3_d" | "python3t" | "python3t_d"
+ ) {
+ return true;
+ }
+
+ // support raw-dylib linking for all CPython versions supported, plus the next prerelease
+ for i in SUPPORTED_VERSIONS_CPYTHON.min.minor..=SUPPORTED_VERSIONS_CPYTHON.max.minor + 1 {
+ if lib_name == format!("python3{i}") || lib_name == format!("python3{i}_d") {
+ return true;
+ }
+ if i >= 13 && (lib_name == format!("python3{i}t") || lib_name == format!("python3{i}t_d")) {
+ return true;
+ }
+ }
+ // PyPy DLL names (libpypy3.X-c.dll)
+ for i in SUPPORTED_VERSIONS_PYPY.min.minor..=SUPPORTED_VERSIONS_PYPY.max.minor {
+ if lib_name == format!("libpypy3.{i}-c") {
+ return true;
+ }
+ }
+
+ false
+}
+
+/// Whether to use raw-dylib linking.
+///
+/// Currently, this only applies if all of the following are true:
+/// - The target OS is Windows.
+/// - The Python library name is one of the [known subset][lib_name_is_known_for_raw_dylib].
+/// - The `PYO3_USE_RAW_DYLIB` environment variable is not set, or is set to `1`.
+///
+/// NB in some cases (e.g. mixed C / Rust builds) it might be necessary to link the full Python
+/// library rather than rely on the symbols which PyO3 defines as raw-dylib, which is why
+/// we have the opt-out env var.
+fn should_use_raw_dylib_linking(lib_name: &str) -> bool {
+ let target_os = cargo_env_var("CARGO_CFG_TARGET_OS").unwrap();
+ if target_os != "windows" {
+ return false;
+ }
+
+ match (
+ lib_name_is_known_for_raw_dylib(lib_name),
+ env_var("PYO3_USE_RAW_DYLIB"),
+ ) {
+ (true, None) => true,
+ (true, Some(os_str)) if os_str == "1" => true,
+ (false, Some(os_str)) if os_str == "1" => {
+ warn!(
+ "PYO3_USE_RAW_DYLIB is set to 1 but the Python library name is not recognized. \
+ Falling back to full linking."
+ );
+ false
+ }
+ _ => false,
+ }
+}
+
fn emit_link_config(build_config: &BuildConfig) -> Result<()> {
- let interpreter_config = &build_config.interpreter_config;
let target_os = cargo_env_var("CARGO_CFG_TARGET_OS").unwrap();
+ let interpreter_config = &build_config.interpreter_config;

let lib_name = interpreter_config
.lib_name()
.ok_or("attempted to link to Python shared library but config does not contain lib_name")?;

- if target_os == "windows" {
+ if should_use_raw_dylib_linking(lib_name) {
// Use raw-dylib linking: emit a cfg so that `extern_libpython!` picks the
// right `#[link(name = "...", kind = "raw-dylib")]` attribute at compile time.
// This eliminates the need for import libraries (.lib files) entirely.
@@ -207,27 +271,36 @@ fn emit_link_config(build_config: &BuildConfig) -> Result<()> {
// Note: raw-dylib is inherently dynamic linking. Static embedding of the
// Python interpreter on Windows is not supported by this path (and is not
// officially supported by CPython on Windows).
+ println!("cargo:rustc-cfg=pyo3_use_raw_dylib");
println!("cargo:rustc-cfg=pyo3_dll=\"{lib_name}\"");
- } else {
- println!(
- "cargo:rustc-link-lib={link_model}{lib_name}",
- link_model = if interpreter_config.shared() {
- ""
- } else {
- "static="
- },
- );
+ return Ok(());
+ }

- if let Some(lib_dir) = interpreter_config.lib_dir() {
- println!("cargo:rustc-link-search=native={lib_dir}");
- } else if matches!(build_config.source, BuildConfigSource::CrossCompile) {
- warn!(
- "The output binary will link to libpython, \
- but PYO3_CROSS_LIB_DIR environment variable is not set. \
- Ensure that the target Python library directory is \
- in the rustc native library search path."
- );
+ println!(
+ "cargo:rustc-link-lib={link_model}{alias}{lib_name}",
+ link_model = if interpreter_config.shared() {
+ ""
+ } else {
+ "static="
+ },
+ // on windows we emit `#[link(name = "pythonXY")]` attributes
+ // and need this alias here to get the right name for the final link
+ alias = if target_os == "windows" {
+ "pythonXY:"
+ } else {
+ ""
}
+ );
+
+ if let Some(lib_dir) = interpreter_config.lib_dir() {
+ println!("cargo:rustc-link-search=native={lib_dir}");
+ } else if matches!(build_config.source, BuildConfigSource::CrossCompile) {
+ warn!(
+ "The output binary will link to libpython, \
+ but PYO3_CROSS_LIB_DIR environment variable is not set. \
+ Ensure that the target Python library directory is \
+ in the rustc native library search path."
+ );
}

Ok(())
--- a/pyo3-ffi/src/impl_/macros.rs
+++ b/pyo3-ffi/src/impl_/macros.rs
@@ -268,10 +268,12 @@ macro_rules! extern_libpython {
"python313", "python313_d",
"python314", "python314_d",
"python315", "python315_d",
+ "python316", "python316_d",
// free-threaded builds (3.13+)
"python313t", "python313t_d",
"python314t", "python314t_d",
"python315t", "python315t_d",
+ "python316t", "python316t_d",
// PyPy (DLL is libpypy3.X-c.dll, not pythonXY.dll)
"libpypy3.11-c",
);
@@ -286,11 +288,12 @@ macro_rules! extern_libpython {
// separate cfg_attr arms per architecture.
(@impl $abi:literal { $($body:tt)* } $($dll:literal),* $(,)?) => {
$(
- #[cfg_attr(all(windows, target_arch = "x86", pyo3_dll = $dll),
+ #[cfg_attr(all(windows, pyo3_use_raw_dylib, target_arch = "x86", pyo3_dll = $dll),
link(name = $dll, kind = "raw-dylib", import_name_type = "undecorated"))]
- #[cfg_attr(all(windows, not(target_arch = "x86"), pyo3_dll = $dll),
+ #[cfg_attr(all(windows, pyo3_use_raw_dylib, not(target_arch = "x86"), pyo3_dll = $dll),
link(name = $dll, kind = "raw-dylib"))]
)*
+ #[cfg_attr(all(windows, not(pyo3_use_raw_dylib)), link(name = "pythonXY"))]
extern $abi {
extern_libpython_items! { $($body)* }
}
4 changes: 2 additions & 2 deletions mingw-w64-python-pyopenssl/PKGBUILD
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
_realname=pyopenssl
pkgbase=mingw-w64-python-${_realname}
pkgname=("${MINGW_PACKAGE_PREFIX}-python-${_realname}")
pkgver=26.2.0
pkgver=26.3.0
pkgrel=1
pkgdesc="Python wrapper module around the OpenSSL library (mingw-w64)"
arch=('any')
Expand All @@ -26,7 +26,7 @@ makedepends=("${MINGW_PACKAGE_PREFIX}-python-build"
"${MINGW_PACKAGE_PREFIX}-python-setuptools")
checkdepends=("${MINGW_PACKAGE_PREFIX}-python-pytest")
source=("https://pypi.org/packages/source/${_realname::1}/${_realname}/${_realname}-${pkgver}.tar.gz")
sha256sums=('8c6fcecd1183a7fc897548dfe388b0cdb7f37e018200d8409cf33959dbe35387')
sha256sums=('589de7fae1c9ea670d18422ed00fc04da787bbde8e1454aea872aa57b49ad341')

build() {
cp -r "${_realname}-${pkgver}" "python-build-${MSYSTEM}" && cd "python-build-${MSYSTEM}"
Expand Down
Loading