@@ -6,7 +6,7 @@ use crate::pyproject_toml::ToolMaturin;
6
6
use crate :: python_interpreter:: { InterpreterConfig , InterpreterKind } ;
7
7
use crate :: { Bindings , BridgeModel , BuildContext , PythonInterpreter , Target } ;
8
8
use anyhow:: { bail, format_err, Context , Result } ;
9
- use cargo_metadata:: { CrateType , TargetKind } ;
9
+ use cargo_metadata:: { CrateType , PackageId , TargetKind } ;
10
10
use cargo_metadata:: { Metadata , Node } ;
11
11
use cargo_options:: heading;
12
12
use pep440_rs:: VersionSpecifiers ;
@@ -934,46 +934,34 @@ fn filter_cargo_targets(
934
934
}
935
935
936
936
/// pyo3 supports building abi3 wheels if the unstable-api feature is not selected
937
- fn has_abi3 ( cargo_metadata : & Metadata ) -> Result < Option < ( u8 , u8 ) > > {
938
- let resolve = cargo_metadata
939
- . resolve
940
- . as_ref ( )
941
- . context ( "Expected cargo to return metadata with resolve" ) ?;
937
+ fn has_abi3 ( deps : & HashMap < & str , & Node > ) -> Result < Option < ( u8 , u8 ) > > {
942
938
for & lib in PYO3_BINDING_CRATES . iter ( ) {
943
- let pyo3_packages = resolve
944
- . nodes
945
- . iter ( )
946
- . filter ( |package| cargo_metadata[ & package. id ] . name . as_str ( ) == lib)
947
- . collect :: < Vec < _ > > ( ) ;
948
- match pyo3_packages. as_slice ( ) {
949
- [ pyo3_crate] => {
950
- // Find the minimal abi3 python version. If there is none, abi3 hasn't been selected
951
- // This parser abi3-py{major}{minor} and returns the minimal (major, minor) tuple
952
- let abi3_selected = pyo3_crate. features . iter ( ) . any ( |x| x == "abi3" ) ;
939
+ if let Some ( pyo3_crate) = deps. get ( lib) {
940
+ // Find the minimal abi3 python version. If there is none, abi3 hasn't been selected
941
+ // This parser abi3-py{major}{minor} and returns the minimal (major, minor) tuple
942
+ let abi3_selected = pyo3_crate. features . iter ( ) . any ( |x| x == "abi3" ) ;
953
943
954
- let min_abi3_version = pyo3_crate
955
- . features
956
- . iter ( )
957
- . filter ( |x| x. starts_with ( "abi3-py" ) && x. len ( ) >= "abi3-pyxx" . len ( ) )
958
- . map ( |x| {
959
- Ok ( (
960
- ( x. as_bytes ( ) [ 7 ] as char ) . to_string ( ) . parse :: < u8 > ( ) ?,
961
- x[ 8 ..] . parse :: < u8 > ( ) ?,
962
- ) )
963
- } )
964
- . collect :: < Result < Vec < ( u8 , u8 ) > > > ( )
965
- . context ( format ! ( "Bogus {lib} cargo features" ) ) ?
966
- . into_iter ( )
967
- . min ( ) ;
968
- if abi3_selected && min_abi3_version. is_none ( ) {
969
- bail ! (
944
+ let min_abi3_version = pyo3_crate
945
+ . features
946
+ . iter ( )
947
+ . filter ( |x| x. starts_with ( "abi3-py" ) && x. len ( ) >= "abi3-pyxx" . len ( ) )
948
+ . map ( |x| {
949
+ Ok ( (
950
+ ( x. as_bytes ( ) [ 7 ] as char ) . to_string ( ) . parse :: < u8 > ( ) ?,
951
+ x[ 8 ..] . parse :: < u8 > ( ) ?,
952
+ ) )
953
+ } )
954
+ . collect :: < Result < Vec < ( u8 , u8 ) > > > ( )
955
+ . context ( format ! ( "Bogus {lib} cargo features" ) ) ?
956
+ . into_iter ( )
957
+ . min ( ) ;
958
+ if abi3_selected && min_abi3_version. is_none ( ) {
959
+ bail ! (
970
960
"You have selected the `abi3` feature but not a minimum version (e.g. the `abi3-py36` feature). \
971
961
maturin needs a minimum version feature to build abi3 wheels."
972
962
)
973
- }
974
- return Ok ( min_abi3_version) ;
975
963
}
976
- _ => continue ,
964
+ return Ok ( min_abi3_version ) ;
977
965
}
978
966
}
979
967
Ok ( None )
@@ -1034,18 +1022,47 @@ fn find_bindings(
1034
1022
}
1035
1023
}
1036
1024
1037
- /// Tries to determine the [BridgeModel] for the target crate
1038
- pub fn find_bridge ( cargo_metadata : & Metadata , bridge : Option < & str > ) -> Result < BridgeModel > {
1025
+ /// Return a map with all (transitive) dependencies of the *current* crate.
1026
+ /// This is different from `metadata.resolve`, which also includes packages
1027
+ /// that are used in the same workspace, but on which the current crate does not depend.
1028
+ fn current_crate_dependencies ( cargo_metadata : & Metadata ) -> Result < HashMap < & str , & Node > > {
1039
1029
let resolve = cargo_metadata
1040
1030
. resolve
1041
1031
. as_ref ( )
1042
- . ok_or_else ( || format_err ! ( "Expected to get a dependency graph from cargo" ) ) ?;
1032
+ . context ( "Expected to get a dependency graph from cargo" ) ?;
1033
+ let root = resolve
1034
+ . root
1035
+ . as_ref ( )
1036
+ . context ( "expected to get a root package" ) ?;
1037
+ let nodes: HashMap < & PackageId , & Node > =
1038
+ resolve. nodes . iter ( ) . map ( |node| ( & node. id , node) ) . collect ( ) ;
1039
+
1040
+ // Walk the dependency tree to get all (in)direct children.
1041
+ let mut dep_ids = HashSet :: with_capacity ( nodes. len ( ) ) ;
1042
+ let mut todo = Vec :: from ( [ root] ) ;
1043
+ while let Some ( id) = todo. pop ( ) {
1044
+ for dep in nodes[ id] . deps . iter ( ) {
1045
+ if dep_ids. contains ( & dep. pkg ) {
1046
+ continue ;
1047
+ }
1048
+ dep_ids. insert ( & dep. pkg ) ;
1049
+ todo. push ( & dep. pkg ) ;
1050
+ }
1051
+ }
1043
1052
1044
- let deps: HashMap < & str , & Node > = resolve
1045
- . nodes
1046
- . iter ( )
1047
- . map ( |node| ( cargo_metadata[ & node. id ] . name . as_ref ( ) , node) )
1048
- . collect ( ) ;
1053
+ Ok ( nodes
1054
+ . into_iter ( )
1055
+ . filter_map ( |( id, node) | {
1056
+ dep_ids
1057
+ . contains ( & id)
1058
+ . then_some ( ( cargo_metadata[ id] . name . as_ref ( ) , node) )
1059
+ } )
1060
+ . collect ( ) )
1061
+ }
1062
+
1063
+ /// Tries to determine the [BridgeModel] for the target crate
1064
+ pub fn find_bridge ( cargo_metadata : & Metadata , bridge : Option < & str > ) -> Result < BridgeModel > {
1065
+ let deps = current_crate_dependencies ( cargo_metadata) ?;
1049
1066
let packages: HashMap < & str , & cargo_metadata:: Package > = cargo_metadata
1050
1067
. packages
1051
1068
. iter ( )
@@ -1141,7 +1158,7 @@ pub fn find_bridge(cargo_metadata: &Metadata, bridge: Option<&str>) -> Result<Br
1141
1158
) ;
1142
1159
}
1143
1160
1144
- return if let Some ( ( major, minor) ) = has_abi3 ( cargo_metadata ) ? {
1161
+ return if let Some ( ( major, minor) ) = has_abi3 ( & deps ) ? {
1145
1162
eprintln ! ( "🔗 Found {lib} bindings with abi3 support for Python ≥ {major}.{minor}" ) ;
1146
1163
let version = packages[ lib] . version . clone ( ) ;
1147
1164
let bindings = Bindings {
0 commit comments