@@ -648,7 +648,6 @@ const GLOBAL_EXTENSIONS: &[&str] = &[
648648 "_weakref" ,
649649 "array" ,
650650 "atexit" ,
651- "audioop" ,
652651 "binascii" ,
653652 "builtins" ,
654653 "cmath" ,
@@ -675,13 +674,17 @@ const GLOBAL_EXTENSIONS: &[&str] = &[
675674// _testsinglephase added in 3.12.
676675// _sha256 and _sha512 merged into _sha2 in 3.12.
677676// _xxinterpchannels added in 3.12.
677+ // audioop removed in 3.13
678+ // _crypt removed in 3.13
679+ // spwd removed in Python 3.13
678680
679681// We didn't build ctypes_test until 3.9.
680682// We didn't build some test extensions until 3.9.
681683
682684const GLOBAL_EXTENSIONS_PYTHON_3_8 : & [ & str ] = & [ "_sha256" , "_sha512" , "parser" ] ;
683685
684686const GLOBAL_EXTENSIONS_PYTHON_3_9 : & [ & str ] = & [
687+ "audioop" ,
685688 "_peg_parser" ,
686689 "_sha256" ,
687690 "_sha512" ,
@@ -692,6 +695,7 @@ const GLOBAL_EXTENSIONS_PYTHON_3_9: &[&str] = &[
692695] ;
693696
694697const GLOBAL_EXTENSIONS_PYTHON_3_10 : & [ & str ] = & [
698+ "audioop" ,
695699 "_sha256" ,
696700 "_sha512" ,
697701 "_uuid" ,
@@ -700,6 +704,7 @@ const GLOBAL_EXTENSIONS_PYTHON_3_10: &[&str] = &[
700704] ;
701705
702706const GLOBAL_EXTENSIONS_PYTHON_3_11 : & [ & str ] = & [
707+ "audioop" ,
703708 "_sha256" ,
704709 "_sha512" ,
705710 "_tokenize" ,
@@ -710,6 +715,7 @@ const GLOBAL_EXTENSIONS_PYTHON_3_11: &[&str] = &[
710715] ;
711716
712717const GLOBAL_EXTENSIONS_PYTHON_3_12 : & [ & str ] = & [
718+ "audioop" ,
713719 "_sha2" ,
714720 "_tokenize" ,
715721 "_typing" ,
@@ -722,14 +728,19 @@ const GLOBAL_EXTENSIONS_PYTHON_3_13: &[&str] = &[
722728 "_sha2" ,
723729 "_tokenize" ,
724730 "_typing" ,
725- "_xxinterpchannels " ,
726- "_xxsubinterpreters " ,
731+ "_interpchannels " ,
732+ "_subinterpreters " ,
727733 "_zoneinfo" ,
734+ "_interpreters" ,
735+ "_suggestions" ,
736+ "_sysconfig" ,
737+ "_testexternalinspection" ,
728738] ;
729739
730740const GLOBAL_EXTENSIONS_MACOS : & [ & str ] = & [ "_scproxy" ] ;
731741
732- const GLOBAL_EXTENSIONS_POSIX : & [ & str ] = & [
742+ // TODO(zanieb): Consider replicating this explicitly for each Python version.
743+ const GLOBAL_EXTENSIONS_POSIX_PRE_313 : & [ & str ] = & [
733744 "_crypt" ,
734745 "_ctypes_test" ,
735746 "_curses" ,
@@ -748,7 +759,26 @@ const GLOBAL_EXTENSIONS_POSIX: &[&str] = &[
748759 "termios" ,
749760] ;
750761
751- const GLOBAL_EXTENSIONS_LINUX : & [ & str ] = & [ "spwd" ] ;
762+ const GLOBAL_EXTENSIONS_POSIX_POST_313 : & [ & str ] = & [
763+ "_ctypes_test" ,
764+ "_curses" ,
765+ "_curses_panel" ,
766+ "_dbm" ,
767+ "_posixshmem" ,
768+ "_posixsubprocess" ,
769+ "_testinternalcapi" ,
770+ "fcntl" ,
771+ "grp" ,
772+ "posix" ,
773+ "pwd" ,
774+ "readline" ,
775+ "resource" ,
776+ "syslog" ,
777+ "termios" ,
778+ ] ;
779+
780+ const GLOBAL_EXTENSIONS_LINUX_PRE_313 : & [ & str ] = & [ "spwd" ] ;
781+ const GLOBAL_EXTENSIONS_LINUX_POST_313 : & [ & str ] = & [ ] ;
752782
753783const GLOBAL_EXTENSIONS_WINDOWS : & [ & str ] = & [
754784 "_msi" ,
@@ -1004,20 +1034,18 @@ fn validate_elf<'data, Elf: FileHeader<Endian = Endianness>>(
10041034 if let Some ( version) = version_version {
10051035 let parts: Vec < & str > = version. splitn ( 2 , '_' ) . collect ( ) ;
10061036
1007- if parts. len ( ) == 2 {
1008- if parts[ 0 ] == "GLIBC" {
1009- let v = version_compare:: Version :: from ( parts[ 1 ] )
1010- . expect ( "unable to parse version" ) ;
1037+ if parts. len ( ) == 2 && parts[ 0 ] == "GLIBC" {
1038+ let v = version_compare:: Version :: from ( parts[ 1 ] )
1039+ . expect ( "unable to parse version" ) ;
10111040
1012- if & v > wanted_glibc_max_version {
1013- context. errors . push ( format ! (
1014- "{} references too new glibc symbol {:?} ({} > {})" ,
1015- path. display( ) ,
1016- name,
1017- v,
1018- wanted_glibc_max_version,
1019- ) ) ;
1020- }
1041+ if & v > wanted_glibc_max_version {
1042+ context. errors . push ( format ! (
1043+ "{} references too new glibc symbol {:?} ({} > {})" ,
1044+ path. display( ) ,
1045+ name,
1046+ v,
1047+ wanted_glibc_max_version,
1048+ ) ) ;
10211049 }
10221050 }
10231051 }
@@ -1045,12 +1073,8 @@ fn validate_elf<'data, Elf: FileHeader<Endian = Endianness>>(
10451073 if let Some ( filename) = path. file_name ( ) {
10461074 let filename = filename. to_string_lossy ( ) ;
10471075
1048- if filename. starts_with ( "libpython" ) && filename. ends_with ( ".so.1.0" ) {
1049- if matches ! ( symbol. st_bind( ) , STB_GLOBAL | STB_WEAK )
1050- && symbol. st_visibility ( ) == STV_DEFAULT
1051- {
1052- context. libpython_exported_symbols . insert ( name. to_string ( ) ) ;
1053- }
1076+ if filename. starts_with ( "libpython" ) && filename. ends_with ( ".so.1.0" ) && matches ! ( symbol. st_bind( ) , STB_GLOBAL | STB_WEAK ) && symbol. st_visibility ( ) == STV_DEFAULT {
1077+ context. libpython_exported_symbols . insert ( name. to_string ( ) ) ;
10541078 }
10551079 }
10561080 }
@@ -1144,7 +1168,7 @@ fn validate_macho<Mach: MachHeader<Endian = Endianness>>(
11441168 target_version = Some ( parse_version_nibbles ( v. version . get ( endian) ) ) ;
11451169 }
11461170 LoadCommandVariant :: Dylib ( command) => {
1147- let raw_string = load_command. string ( endian, command. dylib . name . clone ( ) ) ?;
1171+ let raw_string = load_command. string ( endian, command. dylib . name ) ?;
11481172 let lib = String :: from_utf8 ( raw_string. to_vec ( ) ) ?;
11491173
11501174 dylib_names. push ( lib. clone ( ) ) ;
@@ -1355,9 +1379,9 @@ fn validate_possible_object_file(
13551379 json,
13561380 triple,
13571381 python_major_minor,
1358- path. as_ref ( ) ,
1382+ path,
13591383 header,
1360- & data,
1384+ data,
13611385 ) ?;
13621386 }
13631387 FileKind :: Elf64 => {
@@ -1368,9 +1392,9 @@ fn validate_possible_object_file(
13681392 json,
13691393 triple,
13701394 python_major_minor,
1371- path. as_ref ( ) ,
1395+ path,
13721396 header,
1373- & data,
1397+ data,
13741398 ) ?;
13751399 }
13761400 FileKind :: MachO32 => {
@@ -1386,9 +1410,9 @@ fn validate_possible_object_file(
13861410 json. apple_sdk_version
13871411 . as_ref ( )
13881412 . expect ( "apple_sdk_version should be set" ) ,
1389- path. as_ref ( ) ,
1413+ path,
13901414 header,
1391- & data,
1415+ data,
13921416 ) ?;
13931417 }
13941418 FileKind :: MachO64 => {
@@ -1404,9 +1428,9 @@ fn validate_possible_object_file(
14041428 json. apple_sdk_version
14051429 . as_ref ( )
14061430 . expect ( "apple_sdk_version should be set" ) ,
1407- path. as_ref ( ) ,
1431+ path,
14081432 header,
1409- & data,
1433+ data,
14101434 ) ?;
14111435 }
14121436 FileKind :: MachOFat32 | FileKind :: MachOFat64 => {
@@ -1418,11 +1442,11 @@ fn validate_possible_object_file(
14181442 }
14191443 FileKind :: Pe32 => {
14201444 let file = PeFile32 :: parse ( data) ?;
1421- validate_pe ( & mut context, path. as_ref ( ) , & file) ?;
1445+ validate_pe ( & mut context, path, & file) ?;
14221446 }
14231447 FileKind :: Pe64 => {
14241448 let file = PeFile64 :: parse ( data) ?;
1425- validate_pe ( & mut context, path. as_ref ( ) , & file) ?;
1449+ validate_pe ( & mut context, path, & file) ?;
14261450 }
14271451 _ => { }
14281452 }
@@ -1450,7 +1474,7 @@ fn validate_extension_modules(
14501474 return Ok ( errors) ;
14511475 }
14521476
1453- let mut wanted = BTreeSet :: from_iter ( GLOBAL_EXTENSIONS . iter ( ) . map ( |x| * x ) ) ;
1477+ let mut wanted = BTreeSet :: from_iter ( GLOBAL_EXTENSIONS . iter ( ) . copied ( ) ) ;
14541478
14551479 match python_major_minor {
14561480 "3.8" => {
@@ -1477,7 +1501,17 @@ fn validate_extension_modules(
14771501 }
14781502
14791503 if is_macos {
1480- wanted. extend ( GLOBAL_EXTENSIONS_POSIX ) ;
1504+ match python_major_minor {
1505+ "3.8" | "3.9" | "3.10" | "3.11" | "3.12" => {
1506+ wanted. extend ( GLOBAL_EXTENSIONS_POSIX_PRE_313 ) ;
1507+ }
1508+ "3.13" => {
1509+ wanted. extend ( GLOBAL_EXTENSIONS_POSIX_POST_313 ) ;
1510+ }
1511+ _ => {
1512+ panic ! ( "unhandled Python version: {}" , python_major_minor) ;
1513+ }
1514+ }
14811515 wanted. extend ( GLOBAL_EXTENSIONS_MACOS ) ;
14821516 }
14831517
@@ -1492,15 +1526,42 @@ fn validate_extension_modules(
14921526 }
14931527
14941528 if is_linux {
1495- wanted. extend ( GLOBAL_EXTENSIONS_POSIX ) ;
1496- wanted. extend ( GLOBAL_EXTENSIONS_LINUX ) ;
1529+ match python_major_minor {
1530+ "3.8" | "3.9" | "3.10" | "3.11" | "3.12" => {
1531+ wanted. extend ( GLOBAL_EXTENSIONS_POSIX_PRE_313 ) ;
1532+ }
1533+ "3.13" => {
1534+ wanted. extend ( GLOBAL_EXTENSIONS_POSIX_POST_313 ) ;
1535+ }
1536+ _ => {
1537+ panic ! ( "unhandled Python version: {}" , python_major_minor) ;
1538+ }
1539+ }
1540+ match python_major_minor {
1541+ "3.8" | "3.9" | "3.10" | "3.11" | "3.12" => {
1542+ wanted. extend ( GLOBAL_EXTENSIONS_LINUX_PRE_313 ) ;
1543+ }
1544+ "3.13" => {
1545+ wanted. extend ( GLOBAL_EXTENSIONS_LINUX_POST_313 ) ;
1546+ }
1547+ _ => {
1548+ panic ! ( "unhandled Python version: {}" , python_major_minor) ;
1549+ }
1550+ }
14971551
1498- if !is_linux_musl {
1552+ // Removed in Python 3.13
1553+ if !is_linux_musl && matches ! ( python_major_minor, "3.8" | "3.9" | "3.10" | "3.11" | "3.12" )
1554+ {
14991555 wanted. insert ( "ossaudiodev" ) ;
15001556 }
15011557 }
15021558
1503- if ( is_linux || is_macos) && matches ! ( python_major_minor, "3.9" | "3.10" | "3.11" | "3.12" | "3.13" ) {
1559+ if ( is_linux || is_macos)
1560+ && matches ! (
1561+ python_major_minor,
1562+ "3.9" | "3.10" | "3.11" | "3.12" | "3.13"
1563+ )
1564+ {
15041565 wanted. extend ( [
15051566 "_testbuffer" ,
15061567 "_testimportmultiple" ,
@@ -1604,8 +1665,7 @@ fn validate_json(json: &PythonJsonMain, triple: &str, is_debug: bool) -> Result<
16041665 triple,
16051666 json. crt_features . contains ( & "static" . to_string ( ) ) ,
16061667 & have_extensions,
1607- ) ?
1608- . into_iter ( ) ,
1668+ ) ?,
16091669 ) ;
16101670
16111671 Ok ( errors)
@@ -1659,7 +1719,7 @@ fn validate_distribution(
16591719
16601720 let is_static = triple. contains ( "unknown-linux-musl" ) ;
16611721
1662- let mut tf = crate :: open_distribution_archive ( & dist_path) ?;
1722+ let mut tf = crate :: open_distribution_archive ( dist_path) ?;
16631723
16641724 // First entry in archive should be python/PYTHON.json.
16651725 let mut entries = tf. entries ( ) ?;
@@ -1725,7 +1785,7 @@ fn validate_distribution(
17251785 context. merge ( validate_possible_object_file (
17261786 json. as_ref ( ) . unwrap ( ) ,
17271787 python_major_minor,
1728- & triple,
1788+ triple,
17291789 & path,
17301790 & data,
17311791 ) ?) ;
@@ -1750,9 +1810,9 @@ fn validate_distribution(
17501810 context. merge ( validate_possible_object_file (
17511811 json. as_ref ( ) . unwrap ( ) ,
17521812 python_major_minor,
1753- & triple,
1813+ triple,
17541814 & member_path,
1755- & member_data,
1815+ member_data,
17561816 ) ?) ;
17571817 }
17581818 }
@@ -1938,11 +1998,7 @@ fn validate_distribution(
19381998 } else if triple. contains ( "-windows-" ) {
19391999 false
19402000 // Presence of a shared library extension implies no export.
1941- } else if ext. shared_lib . is_some ( ) {
1942- false
1943- } else {
1944- true
1945- } ;
2001+ } else { ext. shared_lib . is_none ( ) } ;
19462002
19472003 if exported != wanted {
19482004 context. errors . push ( format ! (
@@ -2020,7 +2076,7 @@ fn verify_distribution_behavior(dist_path: &Path) -> Result<Vec<String>> {
20202076 tf. unpack ( temp_dir. path ( ) ) ?;
20212077
20222078 let python_json_path = temp_dir. path ( ) . join ( "python" ) . join ( "PYTHON.json" ) ;
2023- let python_json_data = std:: fs:: read ( & python_json_path) ?;
2079+ let python_json_data = std:: fs:: read ( python_json_path) ?;
20242080 let python_json = parse_python_json ( & python_json_data) ?;
20252081
20262082 let python_exe = temp_dir. path ( ) . join ( "python" ) . join ( python_json. python_exe ) ;
@@ -2029,7 +2085,7 @@ fn verify_distribution_behavior(dist_path: &Path) -> Result<Vec<String>> {
20292085 std:: fs:: write ( & test_file, PYTHON_VERIFICATIONS . as_bytes ( ) ) ?;
20302086
20312087 eprintln ! ( " running interpreter tests (output should follow)" ) ;
2032- let output = duct:: cmd ( & python_exe, & [ test_file. display ( ) . to_string ( ) ] )
2088+ let output = duct:: cmd ( python_exe, [ test_file. display ( ) . to_string ( ) ] )
20332089 . stdout_to_stderr ( )
20342090 . unchecked ( )
20352091 . env ( "TARGET_TRIPLE" , & python_json. target_triple )
0 commit comments