@@ -497,7 +497,7 @@ print("gil_disabled", get_config_var("Py_GIL_DISABLED"))
497
497
let mut lib_dir = None ;
498
498
let mut executable = None ;
499
499
let mut pointer_width = None ;
500
- let mut build_flags = None ;
500
+ let mut build_flags: Option < BuildFlags > = None ;
501
501
let mut suppress_build_script_link_lines = None ;
502
502
let mut extra_build_script_lines = vec ! [ ] ;
503
503
@@ -535,10 +535,12 @@ print("gil_disabled", get_config_var("Py_GIL_DISABLED"))
535
535
let version = version. ok_or ( "missing value for version" ) ?;
536
536
let implementation = implementation. unwrap_or ( PythonImplementation :: CPython ) ;
537
537
let abi3 = abi3. unwrap_or ( false ) ;
538
+ let build_flags = build_flags. unwrap_or_default ( ) ;
539
+ let gil_disabled = build_flags. 0 . contains ( & BuildFlag :: Py_GIL_DISABLED ) ;
538
540
// Fixup lib_name if it's not set
539
541
let lib_name = lib_name. or_else ( || {
540
542
if let Ok ( Ok ( target) ) = env:: var ( "TARGET" ) . map ( |target| target. parse :: < Triple > ( ) ) {
541
- default_lib_name_for_target ( version, implementation, abi3, & target)
543
+ default_lib_name_for_target ( version, implementation, abi3, gil_disabled , & target)
542
544
} else {
543
545
None
544
546
}
@@ -553,7 +555,7 @@ print("gil_disabled", get_config_var("Py_GIL_DISABLED"))
553
555
lib_dir,
554
556
executable,
555
557
pointer_width,
556
- build_flags : build_flags . unwrap_or_default ( ) ,
558
+ build_flags,
557
559
suppress_build_script_link_lines : suppress_build_script_link_lines. unwrap_or ( false ) ,
558
560
extra_build_script_lines,
559
561
} )
@@ -565,7 +567,10 @@ print("gil_disabled", get_config_var("Py_GIL_DISABLED"))
565
567
// Auto generate python3.dll import libraries for Windows targets.
566
568
if self . lib_dir . is_none ( ) {
567
569
let target = target_triple_from_env ( ) ;
568
- let py_version = if self . implementation == PythonImplementation :: CPython && self . abi3 {
570
+ let py_version = if self . implementation == PythonImplementation :: CPython
571
+ && self . abi3
572
+ && !self . is_free_threaded ( )
573
+ {
569
574
None
570
575
} else {
571
576
Some ( self . version )
@@ -893,6 +898,9 @@ pub struct CrossCompileConfig {
893
898
894
899
/// The compile target triple (e.g. aarch64-unknown-linux-gnu)
895
900
target : Triple ,
901
+
902
+ /// Python ABI flags, used to detect free-threaded Python builds.
903
+ abiflags : Option < String > ,
896
904
}
897
905
898
906
impl CrossCompileConfig {
@@ -907,7 +915,7 @@ impl CrossCompileConfig {
907
915
) -> Result < Option < Self > > {
908
916
if env_vars. any ( ) || Self :: is_cross_compiling_from_to ( host, target) {
909
917
let lib_dir = env_vars. lib_dir_path ( ) ?;
910
- let version = env_vars. parse_version ( ) ?;
918
+ let ( version, abiflags ) = env_vars. parse_version ( ) ?;
911
919
let implementation = env_vars. parse_implementation ( ) ?;
912
920
let target = target. clone ( ) ;
913
921
@@ -916,6 +924,7 @@ impl CrossCompileConfig {
916
924
version,
917
925
implementation,
918
926
target,
927
+ abiflags,
919
928
} ) )
920
929
} else {
921
930
Ok ( None )
@@ -989,22 +998,25 @@ impl CrossCompileEnvVars {
989
998
}
990
999
991
1000
/// Parses `PYO3_CROSS_PYTHON_VERSION` environment variable value
992
- /// into `PythonVersion`.
993
- fn parse_version ( & self ) -> Result < Option < PythonVersion > > {
994
- let version = self
995
- . pyo3_cross_python_version
996
- . as_ref ( )
997
- . map ( |os_string| {
1001
+ /// into `PythonVersion` and ABI flags.
1002
+ fn parse_version ( & self ) -> Result < ( Option < PythonVersion > , Option < String > ) > {
1003
+ match self . pyo3_cross_python_version . as_ref ( ) {
1004
+ Some ( os_string) => {
998
1005
let utf8_str = os_string
999
1006
. to_str ( )
1000
1007
. ok_or ( "PYO3_CROSS_PYTHON_VERSION is not valid a UTF-8 string" ) ?;
1001
- utf8_str
1008
+ let ( utf8_str, abiflags) = if let Some ( version) = utf8_str. strip_suffix ( 't' ) {
1009
+ ( version, Some ( "t" . to_string ( ) ) )
1010
+ } else {
1011
+ ( utf8_str, None )
1012
+ } ;
1013
+ let version = utf8_str
1002
1014
. parse ( )
1003
- . context ( "failed to parse PYO3_CROSS_PYTHON_VERSION" )
1004
- } )
1005
- . transpose ( ) ? ;
1006
-
1007
- Ok ( version )
1015
+ . context ( "failed to parse PYO3_CROSS_PYTHON_VERSION" ) ? ;
1016
+ Ok ( ( Some ( version ) , abiflags ) )
1017
+ }
1018
+ None => Ok ( ( None , None ) ) ,
1019
+ }
1008
1020
}
1009
1021
1010
1022
/// Parses `PYO3_CROSS_PYTHON_IMPLEMENTATION` environment variable value
@@ -1530,16 +1542,27 @@ fn default_cross_compile(cross_compile_config: &CrossCompileConfig) -> Result<In
1530
1542
let implementation = cross_compile_config
1531
1543
. implementation
1532
1544
. unwrap_or ( PythonImplementation :: CPython ) ;
1545
+ let gil_disabled = cross_compile_config. abiflags . as_deref ( ) == Some ( "t" ) ;
1533
1546
1534
- let lib_name =
1535
- default_lib_name_for_target ( version, implementation, abi3, & cross_compile_config. target ) ;
1547
+ let lib_name = default_lib_name_for_target (
1548
+ version,
1549
+ implementation,
1550
+ abi3,
1551
+ gil_disabled,
1552
+ & cross_compile_config. target ,
1553
+ ) ;
1536
1554
1537
1555
let mut lib_dir = cross_compile_config. lib_dir_string ( ) ;
1538
1556
1539
1557
// Auto generate python3.dll import libraries for Windows targets.
1540
1558
#[ cfg( feature = "python3-dll-a" ) ]
1541
1559
if lib_dir. is_none ( ) {
1542
- let py_version = if abi3 { None } else { Some ( version) } ;
1560
+ let py_version = if implementation == PythonImplementation :: CPython && abi3 && !gil_disabled
1561
+ {
1562
+ None
1563
+ } else {
1564
+ Some ( version)
1565
+ } ;
1543
1566
lib_dir = self :: import_lib:: generate_import_lib (
1544
1567
& cross_compile_config. target ,
1545
1568
cross_compile_config
@@ -1652,12 +1675,16 @@ fn default_lib_name_for_target(
1652
1675
version : PythonVersion ,
1653
1676
implementation : PythonImplementation ,
1654
1677
abi3 : bool ,
1678
+ gil_disabled : bool ,
1655
1679
target : & Triple ,
1656
1680
) -> Option < String > {
1657
1681
if target. operating_system == OperatingSystem :: Windows {
1658
- Some ( default_lib_name_windows ( version, implementation, abi3, false , false , false ) . unwrap ( ) )
1682
+ Some (
1683
+ default_lib_name_windows ( version, implementation, abi3, false , false , gil_disabled)
1684
+ . unwrap ( ) ,
1685
+ )
1659
1686
} else if is_linking_libpython_for_target ( target) {
1660
- Some ( default_lib_name_unix ( version, implementation, None , false ) . unwrap ( ) )
1687
+ Some ( default_lib_name_unix ( version, implementation, None , gil_disabled ) . unwrap ( ) )
1661
1688
} else {
1662
1689
None
1663
1690
}
@@ -1906,7 +1933,14 @@ pub fn make_interpreter_config() -> Result<InterpreterConfig> {
1906
1933
// Auto generate python3.dll import libraries for Windows targets.
1907
1934
#[ cfg( feature = "python3-dll-a" ) ]
1908
1935
{
1909
- let py_version = if interpreter_config. abi3 {
1936
+ let gil_disabled = interpreter_config
1937
+ . build_flags
1938
+ . 0
1939
+ . contains ( & BuildFlag :: Py_GIL_DISABLED ) ;
1940
+ let py_version = if interpreter_config. implementation == PythonImplementation :: CPython
1941
+ && interpreter_config. abi3
1942
+ && !gil_disabled
1943
+ {
1910
1944
None
1911
1945
} else {
1912
1946
Some ( interpreter_config. version )
@@ -2706,7 +2740,7 @@ mod tests {
2706
2740
2707
2741
assert_eq ! (
2708
2742
env_vars. parse_version( ) . unwrap( ) ,
2709
- Some ( PythonVersion { major: 3 , minor: 9 } )
2743
+ ( Some ( PythonVersion { major: 3 , minor: 9 } ) , None ) ,
2710
2744
) ;
2711
2745
2712
2746
let env_vars = CrossCompileEnvVars {
@@ -2716,7 +2750,25 @@ mod tests {
2716
2750
pyo3_cross_python_implementation : None ,
2717
2751
} ;
2718
2752
2719
- assert_eq ! ( env_vars. parse_version( ) . unwrap( ) , None ) ;
2753
+ assert_eq ! ( env_vars. parse_version( ) . unwrap( ) , ( None , None ) ) ;
2754
+
2755
+ let env_vars = CrossCompileEnvVars {
2756
+ pyo3_cross : None ,
2757
+ pyo3_cross_lib_dir : None ,
2758
+ pyo3_cross_python_version : Some ( "3.13t" . into ( ) ) ,
2759
+ pyo3_cross_python_implementation : None ,
2760
+ } ;
2761
+
2762
+ assert_eq ! (
2763
+ env_vars. parse_version( ) . unwrap( ) ,
2764
+ (
2765
+ Some ( PythonVersion {
2766
+ major: 3 ,
2767
+ minor: 13
2768
+ } ) ,
2769
+ Some ( "t" . into( ) )
2770
+ ) ,
2771
+ ) ;
2720
2772
2721
2773
let env_vars = CrossCompileEnvVars {
2722
2774
pyo3_cross : None ,
@@ -2799,6 +2851,11 @@ mod tests {
2799
2851
version : Some ( interpreter_config. version ) ,
2800
2852
implementation : Some ( interpreter_config. implementation ) ,
2801
2853
target : triple ! ( "x86_64-unknown-linux-gnu" ) ,
2854
+ abiflags : if interpreter_config. is_free_threaded ( ) {
2855
+ Some ( "t" . into ( ) )
2856
+ } else {
2857
+ None
2858
+ } ,
2802
2859
} ;
2803
2860
2804
2861
let sysconfigdata_path = match find_sysconfigdata ( & cross) {
@@ -3074,6 +3131,7 @@ mod tests {
3074
3131
version : None ,
3075
3132
implementation : None ,
3076
3133
target : triple ! ( "x86_64-unknown-linux-gnu" ) ,
3134
+ abiflags : None ,
3077
3135
} )
3078
3136
. unwrap_err ( ) ;
3079
3137
0 commit comments