Skip to content

Commit 7ed0b2f

Browse files
authored
Link against limited API DLL under Cygwin when abi3 is used (#5574)
Like with Windows Python, we need to link to a different DLL which exports the limited API when using abi3. This makes pyo3 link against libpython3.dll instead of libpython3.X.dll when abi3 is enabled. Note: The limited API DLL is currently not provided in cygwin upstream, but only in MSYS2 (downstream): msys2/MSYS2-packages#5751 I've contacted upstream about this change https://cygwin.com/pipermail/cygwin-apps/2025-October/044659.html
1 parent 5e35cc1 commit 7ed0b2f

File tree

2 files changed

+57
-3
lines changed

2 files changed

+57
-3
lines changed

newsfragments/5574.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix linking against the limited API DLL under Cygwin when abi3 is used

pyo3-build-config/src/impl_.rs

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ print_if_set("base_prefix", base_prefix)
263263
print("executable", sys.executable)
264264
print("calcsize_pointer", struct.calcsize("P"))
265265
print("mingw", get_platform().startswith("mingw"))
266+
print("cygwin", get_platform().startswith("cygwin"))
266267
print("ext_suffix", get_config_var("EXT_SUFFIX"))
267268
print("gil_disabled", get_config_var("Py_GIL_DISABLED"))
268269
"#;
@@ -315,6 +316,8 @@ print("gil_disabled", get_config_var("Py_GIL_DISABLED"))
315316
_ => panic!("Unknown Py_GIL_DISABLED value"),
316317
};
317318

319+
let cygwin = map["cygwin"].as_str() == "True";
320+
318321
let lib_name = if cfg!(windows) {
319322
default_lib_name_windows(
320323
version,
@@ -331,6 +334,8 @@ print("gil_disabled", get_config_var("Py_GIL_DISABLED"))
331334
default_lib_name_unix(
332335
version,
333336
implementation,
337+
abi3,
338+
cygwin,
334339
map.get("ld_version").map(String::as_str),
335340
gil_disabled,
336341
)?
@@ -410,9 +415,13 @@ print("gil_disabled", get_config_var("Py_GIL_DISABLED"))
410415
Some(value) => value == "1",
411416
None => false,
412417
};
418+
let cygwin = soabi.ends_with("cygwin");
419+
let abi3 = is_abi3();
413420
let lib_name = Some(default_lib_name_unix(
414421
version,
415422
implementation,
423+
abi3,
424+
cygwin,
416425
sysconfigdata.get_value("LDVERSION"),
417426
gil_disabled,
418427
)?);
@@ -425,7 +434,7 @@ print("gil_disabled", get_config_var("Py_GIL_DISABLED"))
425434
implementation,
426435
version,
427436
shared: shared || framework,
428-
abi3: is_abi3(),
437+
abi3,
429438
lib_dir,
430439
lib_name,
431440
executable: None,
@@ -1714,7 +1723,15 @@ fn default_lib_name_for_target(
17141723
if target.operating_system == OperatingSystem::Windows {
17151724
default_lib_name_windows(version, implementation, abi3, false, false, gil_disabled).unwrap()
17161725
} else {
1717-
default_lib_name_unix(version, implementation, None, gil_disabled).unwrap()
1726+
default_lib_name_unix(
1727+
version,
1728+
implementation,
1729+
abi3,
1730+
target.operating_system == OperatingSystem::Cygwin,
1731+
None,
1732+
gil_disabled,
1733+
)
1734+
.unwrap()
17181735
}
17191736
}
17201737

@@ -1760,14 +1777,18 @@ fn default_lib_name_windows(
17601777
fn default_lib_name_unix(
17611778
version: PythonVersion,
17621779
implementation: PythonImplementation,
1780+
abi3: bool,
1781+
cygwin: bool,
17631782
ld_version: Option<&str>,
17641783
gil_disabled: bool,
17651784
) -> Result<String> {
17661785
match implementation {
17671786
PythonImplementation::CPython => match ld_version {
17681787
Some(ld_version) => Ok(format!("python{ld_version}")),
17691788
None => {
1770-
if version > PythonVersion::PY37 {
1789+
if cygwin && abi3 {
1790+
Ok("python3".to_string())
1791+
} else if version > PythonVersion::PY37 {
17711792
// PEP 3149 ABI version tags are finally gone
17721793
if gil_disabled {
17731794
ensure!(version >= PythonVersion::PY313, "Cannot compile C extensions for the free-threaded build on Python versions earlier than 3.13, found {}.{}", version.major, version.minor);
@@ -2688,6 +2709,8 @@ mod tests {
26882709
super::default_lib_name_unix(
26892710
PythonVersion { major: 3, minor: 7 },
26902711
CPython,
2712+
false,
2713+
false,
26912714
None,
26922715
false
26932716
)
@@ -2699,6 +2722,8 @@ mod tests {
26992722
super::default_lib_name_unix(
27002723
PythonVersion { major: 3, minor: 8 },
27012724
CPython,
2725+
false,
2726+
false,
27022727
None,
27032728
false
27042729
)
@@ -2709,6 +2734,8 @@ mod tests {
27092734
super::default_lib_name_unix(
27102735
PythonVersion { major: 3, minor: 9 },
27112736
CPython,
2737+
false,
2738+
false,
27122739
None,
27132740
false
27142741
)
@@ -2720,6 +2747,8 @@ mod tests {
27202747
super::default_lib_name_unix(
27212748
PythonVersion { major: 3, minor: 9 },
27222749
CPython,
2750+
false,
2751+
false,
27232752
Some("3.7md"),
27242753
false
27252754
)
@@ -2735,6 +2764,8 @@ mod tests {
27352764
minor: 11
27362765
},
27372766
PyPy,
2767+
false,
2768+
false,
27382769
None,
27392770
false
27402771
)
@@ -2746,6 +2777,8 @@ mod tests {
27462777
super::default_lib_name_unix(
27472778
PythonVersion { major: 3, minor: 9 },
27482779
PyPy,
2780+
false,
2781+
false,
27492782
Some("3.11d"),
27502783
false
27512784
)
@@ -2761,6 +2794,8 @@ mod tests {
27612794
minor: 13
27622795
},
27632796
CPython,
2797+
false,
2798+
false,
27642799
None,
27652800
true
27662801
)
@@ -2774,10 +2809,28 @@ mod tests {
27742809
minor: 12,
27752810
},
27762811
CPython,
2812+
false,
2813+
false,
27772814
None,
27782815
true,
27792816
)
27802817
.is_err());
2818+
// cygwin abi3 links to unversioned libpython
2819+
assert_eq!(
2820+
super::default_lib_name_unix(
2821+
PythonVersion {
2822+
major: 3,
2823+
minor: 13
2824+
},
2825+
CPython,
2826+
true,
2827+
true,
2828+
None,
2829+
false
2830+
)
2831+
.unwrap(),
2832+
"python3",
2833+
);
27812834
}
27822835

27832836
#[test]

0 commit comments

Comments
 (0)