@@ -452,7 +452,7 @@ print("gil_disabled", get_config_var("Py_GIL_DISABLED"))
452452 } ;
453453 let cygwin = soabi. ends_with ( "cygwin" ) ;
454454 let mut abi_builder = PythonAbiBuilder :: from_build_env ( implementation, version) ?;
455- if gil_disabled {
455+ if gil_disabled && abi_builder . kind . is_none ( ) {
456456 abi_builder = abi_builder. free_threaded ( ) ?;
457457 }
458458 let target_abi = abi_builder. finalize ( ) ;
@@ -499,7 +499,8 @@ print("gil_disabled", get_config_var("Py_GIL_DISABLED"))
499499 config. target_abi . implementation ,
500500 get_abi3_version ( ) . unwrap_or ( config. target_abi . version ) ,
501501 ) ?;
502- if config. target_abi . kind . is_free_threaded ( ) {
502+ // only allow free-threaded builds if the build environment didn't force an abi3 build
503+ if config. target_abi . kind . is_free_threaded ( ) && abi_builder. kind . is_none ( ) {
503504 abi_builder = abi_builder. free_threaded ( ) ?;
504505 }
505506 config. target_abi = abi_builder. finalize ( ) ;
@@ -591,15 +592,28 @@ print("gil_disabled", get_config_var("Py_GIL_DISABLED"))
591592
592593 let version = version. ok_or ( "missing value for version" ) ?;
593594 let implementation = implementation. unwrap_or ( PythonImplementation :: CPython ) ;
594-
595- let target_abi = if !( target_abi. is_some ( ) || abi3. is_some ( ) ) {
595+ let target_abi = if !( target_abi. is_some ( ) || abi3. is_some ( ) || build_flags. is_some ( ) ) {
596596 PythonAbiBuilder :: new ( implementation, version) . finalize ( )
597597 } else if abi3. is_some ( ) && abi3. unwrap ( ) {
598- // should we produce a user-visible warning about this?
598+ warn ! ( "abi3 configuration file option is deprecated, set target_abi instead" ) ;
599599 PythonAbiBuilder :: new ( implementation, version)
600600 . abi3 ( )
601601 . unwrap ( )
602602 . finalize ( )
603+ } else if let Some ( ref flags) = build_flags {
604+ if flags. 0 . contains ( & BuildFlag :: Py_GIL_DISABLED ) {
605+ PythonAbiBuilder :: new ( implementation, version)
606+ . free_threaded ( )
607+ . unwrap ( )
608+ . finalize ( )
609+ } else {
610+ // we could avoid this branch with if let chains
611+ ensure ! (
612+ !( target_abi. is_some( ) && abi3. is_some( ) ) ,
613+ "Invalid config that sets both target_abi and abi3."
614+ ) ;
615+ target_abi. unwrap_or ( PythonAbiBuilder :: new ( implementation, version) . finalize ( ) )
616+ }
603617 } else {
604618 ensure ! (
605619 !( target_abi. is_some( ) && abi3. is_some( ) ) ,
@@ -737,7 +751,7 @@ print("gil_disabled", get_config_var("Py_GIL_DISABLED"))
737751 }
738752}
739753
740- #[ cfg_attr ( test , derive( Debug ) ) ]
754+ #[ derive( Debug ) ]
741755pub struct InterpreterConfigBuilder {
742756 implementation : PythonImplementation ,
743757 version : PythonVersion ,
@@ -775,7 +789,11 @@ impl InterpreterConfigBuilder {
775789 }
776790
777791 pub fn target_abi ( self , target_abi : PythonAbi ) -> Result < InterpreterConfigBuilder > {
778- ensure ! ( self . target_abi. is_none( ) , "Target ABI already set!" ) ;
792+ ensure ! (
793+ self . target_abi. is_none( ) ,
794+ "Target ABI already set to {:?}" ,
795+ target_abi
796+ ) ;
779797 Ok ( InterpreterConfigBuilder {
780798 target_abi : Some ( target_abi) ,
781799 ..self
@@ -946,7 +964,10 @@ impl PythonAbiBuilder {
946964
947965 pub fn abi3 ( self ) -> Result < PythonAbiBuilder > {
948966 if self . kind . is_some ( ) {
949- bail ! ( "Target ABI already chosen!" )
967+ bail ! (
968+ "ABI kind already set to {:?}, cannot set to abi3" ,
969+ self . kind
970+ )
950971 }
951972
952973 // PyPy and GraalPy don't support abi3; don't adjust the version
@@ -972,7 +993,10 @@ impl PythonAbiBuilder {
972993
973994 pub fn free_threaded ( self ) -> Result < PythonAbiBuilder > {
974995 if self . kind . is_some ( ) {
975- bail ! ( "Target ABI already chosen!" )
996+ bail ! (
997+ "Target ABI already set to {:?}, cannot set to free-threaded" ,
998+ self . kind
999+ )
9761000 }
9771001 if self . version < PythonVersion :: PY313 {
9781002 let version = self . version ;
@@ -1569,8 +1593,8 @@ impl FromStr for BuildFlag {
15691593/// is the equivalent of `#ifdef {varname}` in C.
15701594///
15711595/// see Misc/SpecialBuilds.txt in the python source for what these mean.
1572- #[ cfg_attr( test, derive( Debug , PartialEq , Eq ) ) ]
1573- #[ derive( Clone , Default ) ]
1596+ #[ cfg_attr( test, derive( PartialEq , Eq ) ) ]
1597+ #[ derive( Debug , Clone , Default ) ]
15741598pub struct BuildFlags ( pub HashSet < BuildFlag > ) ;
15751599
15761600impl BuildFlags {
@@ -1979,7 +2003,8 @@ fn default_cross_compile(cross_compile_config: &CrossCompileConfig) -> Result<In
19792003 . unwrap_or ( PythonImplementation :: CPython ) ;
19802004 let gil_disabled: bool = cross_compile_config. abiflags . as_deref ( ) == Some ( "t" ) ;
19812005 let mut abi_builder = PythonAbiBuilder :: from_build_env ( implementation, version) ?;
1982- if gil_disabled {
2006+ // The build environment might imply an abi3 build, which can't be free-threaded
2007+ if gil_disabled && abi_builder. kind . is_none ( ) {
19832008 abi_builder = abi_builder. free_threaded ( ) ?;
19842009 }
19852010 let target_abi = abi_builder. finalize ( ) ;
@@ -2276,7 +2301,7 @@ pub fn make_cross_compile_config() -> Result<Option<InterpreterConfig>> {
22762301 config. target_abi . implementation ,
22772302 get_abi3_version ( ) . unwrap_or ( config. target_abi . version ) ,
22782303 ) ?;
2279- if config. target_abi . kind . is_free_threaded ( ) {
2304+ if config. target_abi . kind . is_free_threaded ( ) && abi_builder . kind . is_none ( ) {
22802305 abi_builder = abi_builder. free_threaded ( ) ?;
22812306 }
22822307 config. target_abi = abi_builder. finalize ( ) ;
0 commit comments