@@ -14,7 +14,6 @@ use jobserver::Client;
14
14
15
15
use core:: { Package , PackageId , PackageSet , Profile , Resolve , Target } ;
16
16
use core:: { Dependency , Profiles , TargetKind , Workspace } ;
17
- use core:: dependency:: Kind as DepKind ;
18
17
use util:: { self , internal, profile, Cfg , CfgExpr , Config , ProcessBuilder } ;
19
18
use util:: errors:: { CargoResult , CargoResultExt } ;
20
19
@@ -25,6 +24,9 @@ use super::layout::Layout;
25
24
use super :: links:: Links ;
26
25
use super :: { BuildConfig , Compilation , Kind } ;
27
26
27
+ mod unit_dependencies;
28
+ use self :: unit_dependencies:: build_unit_dependencies;
29
+
28
30
/// All information needed to define a Unit.
29
31
///
30
32
/// A unit is an object that has enough information so that cargo knows how to build it.
@@ -102,6 +104,7 @@ pub struct Context<'a, 'cfg: 'a> {
102
104
profiles : & ' a Profiles ,
103
105
incremental_env : Option < bool > ,
104
106
107
+ unit_dependencies : Option < HashMap < Unit < ' a > , Vec < Unit < ' a > > > > ,
105
108
/// For each Unit, a list all files produced as a triple of
106
109
///
107
110
/// - File name that will be produced by the build process (in `deps`)
@@ -204,6 +207,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
204
207
jobserver,
205
208
build_script_overridden : HashSet :: new ( ) ,
206
209
210
+ unit_dependencies : None ,
207
211
// TODO: Pre-Calculate these with a topo-sort, rather than lazy-calculating
208
212
target_filenames : HashMap :: new ( ) ,
209
213
target_metadatas : HashMap :: new ( ) ,
@@ -232,6 +236,12 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
232
236
Ok ( ( ) )
233
237
}
234
238
239
+ pub fn build_unit_dependencies ( & mut self , units : & [ Unit < ' a > ] ) -> CargoResult < ( ) > {
240
+ assert ! ( self . unit_dependencies. is_none( ) ) ;
241
+ self . unit_dependencies = Some ( build_unit_dependencies ( units, self ) ?) ;
242
+ Ok ( ( ) )
243
+ }
244
+
235
245
/// Ensure that we've collected all target-specific information to compile
236
246
/// all the units mentioned in `units`.
237
247
pub fn probe_target_info ( & mut self ) -> CargoResult < ( ) > {
@@ -361,7 +371,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
361
371
if is_plugin {
362
372
self . used_in_plugin . insert ( * unit) ;
363
373
}
364
- for unit in self . dep_targets ( unit) ? {
374
+ for unit in self . dep_targets ( unit) {
365
375
self . walk_used_in_plugin_map ( & unit, is_plugin || unit. target . for_host ( ) , visited) ?;
366
376
}
367
377
Ok ( ( ) )
@@ -526,9 +536,10 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
526
536
. hash ( & mut hasher) ;
527
537
528
538
// Mix in the target-metadata of all the dependencies of this target
529
- if let Ok ( deps) = self . dep_targets ( unit) {
530
- let mut deps_metadata = deps. into_iter ( )
531
- . map ( |dep_unit| self . target_metadata ( & dep_unit) )
539
+ {
540
+ let mut deps_metadata = self . dep_targets ( unit)
541
+ . iter ( )
542
+ . map ( |dep_unit| self . target_metadata ( dep_unit) )
532
543
. collect :: < Vec < _ > > ( ) ;
533
544
deps_metadata. sort ( ) ;
534
545
deps_metadata. hash ( & mut hasher) ;
@@ -770,236 +781,25 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
770
781
771
782
/// For a package, return all targets which are registered as dependencies
772
783
/// for that package.
773
- pub fn dep_targets ( & self , unit : & Unit < ' a > ) -> CargoResult < Vec < Unit < ' a > > > {
774
- if unit. profile . run_custom_build {
775
- return self . dep_run_custom_build ( unit) ;
776
- } else if unit. profile . doc && !unit. profile . test {
777
- return self . doc_deps ( unit) ;
778
- }
779
-
780
- let id = unit. pkg . package_id ( ) ;
781
- let deps = self . resolve . deps ( id) ;
782
- let mut ret = deps. filter ( |dep| {
783
- unit. pkg
784
- . dependencies ( )
785
- . iter ( )
786
- . filter ( |d| d. name ( ) == dep. name ( ) && d. version_req ( ) . matches ( dep. version ( ) ) )
787
- . any ( |d| {
788
- // If this target is a build command, then we only want build
789
- // dependencies, otherwise we want everything *other than* build
790
- // dependencies.
791
- if unit. target . is_custom_build ( ) != d. is_build ( ) {
792
- return false ;
793
- }
794
-
795
- // If this dependency is *not* a transitive dependency, then it
796
- // only applies to test/example targets
797
- if !d. is_transitive ( ) && !unit. target . is_test ( ) && !unit. target . is_example ( )
798
- && !unit. profile . test
799
- {
800
- return false ;
801
- }
802
-
803
- // If this dependency is only available for certain platforms,
804
- // make sure we're only enabling it for that platform.
805
- if !self . dep_platform_activated ( d, unit. kind ) {
806
- return false ;
807
- }
808
-
809
- // If the dependency is optional, then we're only activating it
810
- // if the corresponding feature was activated
811
- if d. is_optional ( ) && !self . resolve . features ( id) . contains ( & * d. name ( ) ) {
812
- return false ;
813
- }
814
-
815
- // If we've gotten past all that, then this dependency is
816
- // actually used!
817
- true
818
- } )
819
- } ) . filter_map ( |id| match self . get_package ( id) {
820
- Ok ( pkg) => pkg. targets ( ) . iter ( ) . find ( |t| t. is_lib ( ) ) . map ( |t| {
821
- let unit = Unit {
822
- pkg,
823
- target : t,
824
- profile : self . lib_or_check_profile ( unit, t) ,
825
- kind : unit. kind . for_target ( t) ,
826
- } ;
827
- Ok ( unit)
828
- } ) ,
829
- Err ( e) => Some ( Err ( e) ) ,
830
- } )
831
- . collect :: < CargoResult < Vec < _ > > > ( ) ?;
832
-
833
- // If this target is a build script, then what we've collected so far is
834
- // all we need. If this isn't a build script, then it depends on the
835
- // build script if there is one.
836
- if unit. target . is_custom_build ( ) {
837
- return Ok ( ret) ;
838
- }
839
- ret. extend ( self . dep_build_script ( unit) ) ;
840
-
841
- // If this target is a binary, test, example, etc, then it depends on
842
- // the library of the same package. The call to `resolve.deps` above
843
- // didn't include `pkg` in the return values, so we need to special case
844
- // it here and see if we need to push `(pkg, pkg_lib_target)`.
845
- if unit. target . is_lib ( ) && !unit. profile . doc {
846
- return Ok ( ret) ;
847
- }
848
- ret. extend ( self . maybe_lib ( unit) ) ;
849
-
850
- // Integration tests/benchmarks require binaries to be built
851
- if unit. profile . test && ( unit. target . is_test ( ) || unit. target . is_bench ( ) ) {
852
- ret. extend (
853
- unit. pkg
854
- . targets ( )
855
- . iter ( )
856
- . filter ( |t| {
857
- let no_required_features = Vec :: new ( ) ;
858
-
859
- t. is_bin ( ) &&
860
- // Skip binaries with required features that have not been selected.
861
- t. required_features ( ) . unwrap_or ( & no_required_features) . iter ( ) . all ( |f| {
862
- self . resolve . features ( id) . contains ( f)
863
- } )
864
- } )
865
- . map ( |t| Unit {
866
- pkg : unit. pkg ,
867
- target : t,
868
- profile : self . lib_or_check_profile ( unit, t) ,
869
- kind : unit. kind . for_target ( t) ,
870
- } ) ,
871
- ) ;
872
- }
873
- Ok ( ret)
874
- }
875
-
876
- /// Returns the dependencies needed to run a build script.
877
- ///
878
- /// The `unit` provided must represent an execution of a build script, and
879
- /// the returned set of units must all be run before `unit` is run.
880
- pub fn dep_run_custom_build ( & self , unit : & Unit < ' a > ) -> CargoResult < Vec < Unit < ' a > > > {
784
+ // TODO: this ideally should be `-> &[Unit<'a>]`
785
+ pub fn dep_targets ( & self , unit : & Unit < ' a > ) -> Vec < Unit < ' a > > {
881
786
// If this build script's execution has been overridden then we don't
882
787
// actually depend on anything, we've reached the end of the dependency
883
788
// chain as we've got all the info we're gonna get.
884
- let key = ( unit. pkg . package_id ( ) . clone ( ) , unit. kind ) ;
885
- if self . build_script_overridden . contains ( & key) {
886
- return Ok ( Vec :: new ( ) ) ;
887
- }
888
-
889
- // When not overridden, then the dependencies to run a build script are:
890
789
//
891
- // 1. Compiling the build script itself
892
- // 2. For each immediate dependency of our package which has a `links`
893
- // key, the execution of that build script.
894
- let not_custom_build = unit. pkg
895
- . targets ( )
896
- . iter ( )
897
- . find ( |t| !t. is_custom_build ( ) )
898
- . unwrap ( ) ;
899
- let tmp = Unit {
900
- target : not_custom_build,
901
- profile : & self . profiles . dev ,
902
- ..* unit
903
- } ;
904
- let deps = self . dep_targets ( & tmp) ?;
905
- Ok ( deps. iter ( )
906
- . filter_map ( |unit| {
907
- if !unit. target . linkable ( ) || unit. pkg . manifest ( ) . links ( ) . is_none ( ) {
908
- return None ;
909
- }
910
- self . dep_build_script ( unit)
911
- } )
912
- . chain ( Some ( Unit {
913
- profile : self . build_script_profile ( unit. pkg . package_id ( ) ) ,
914
- kind : Kind :: Host , // build scripts always compiled for the host
915
- ..* unit
916
- } ) )
917
- . collect ( ) )
918
- }
919
-
920
- /// Returns the dependencies necessary to document a package
921
- fn doc_deps ( & self , unit : & Unit < ' a > ) -> CargoResult < Vec < Unit < ' a > > > {
922
- let deps = self . resolve
923
- . deps ( unit. pkg . package_id ( ) )
924
- . filter ( |dep| {
925
- unit. pkg
926
- . dependencies ( )
927
- . iter ( )
928
- . filter ( |d| d. name ( ) == dep. name ( ) )
929
- . any ( |dep| match dep. kind ( ) {
930
- DepKind :: Normal => self . dep_platform_activated ( dep, unit. kind ) ,
931
- _ => false ,
932
- } )
933
- } )
934
- . map ( |dep| self . get_package ( dep) ) ;
935
-
936
- // To document a library, we depend on dependencies actually being
937
- // built. If we're documenting *all* libraries, then we also depend on
938
- // the documentation of the library being built.
939
- let mut ret = Vec :: new ( ) ;
940
- for dep in deps {
941
- let dep = dep?;
942
- let lib = match dep. targets ( ) . iter ( ) . find ( |t| t. is_lib ( ) ) {
943
- Some ( lib) => lib,
944
- None => continue ,
945
- } ;
946
- ret. push ( Unit {
947
- pkg : dep,
948
- target : lib,
949
- profile : self . lib_or_check_profile ( unit, lib) ,
950
- kind : unit. kind . for_target ( lib) ,
951
- } ) ;
952
- if self . build_config . doc_all {
953
- ret. push ( Unit {
954
- pkg : dep,
955
- target : lib,
956
- profile : & self . profiles . doc ,
957
- kind : unit. kind . for_target ( lib) ,
958
- } ) ;
790
+ // Note there's a subtlety about this piece of code! The
791
+ // `build_script_overridden` map here is populated in
792
+ // `custom_build::build_map` which you need to call before inspecting
793
+ // dependencies. However, that code itself calls this method and
794
+ // gets a full pre-filtered set of dependencies. This is not super
795
+ // obvious, and clear, but it does work at the moment.
796
+ if unit. profile . run_custom_build {
797
+ let key = ( unit. pkg . package_id ( ) . clone ( ) , unit. kind ) ;
798
+ if self . build_script_overridden . contains ( & key) {
799
+ return Vec :: new ( ) ;
959
800
}
960
801
}
961
-
962
- // Be sure to build/run the build script for documented libraries as
963
- ret. extend ( self . dep_build_script ( unit) ) ;
964
-
965
- // If we document a binary, we need the library available
966
- if unit. target . is_bin ( ) {
967
- ret. extend ( self . maybe_lib ( unit) ) ;
968
- }
969
- Ok ( ret)
970
- }
971
-
972
- /// If a build script is scheduled to be run for the package specified by
973
- /// `unit`, this function will return the unit to run that build script.
974
- ///
975
- /// Overriding a build script simply means that the running of the build
976
- /// script itself doesn't have any dependencies, so even in that case a unit
977
- /// of work is still returned. `None` is only returned if the package has no
978
- /// build script.
979
- fn dep_build_script ( & self , unit : & Unit < ' a > ) -> Option < Unit < ' a > > {
980
- unit. pkg
981
- . targets ( )
982
- . iter ( )
983
- . find ( |t| t. is_custom_build ( ) )
984
- . map ( |t| Unit {
985
- pkg : unit. pkg ,
986
- target : t,
987
- profile : & self . profiles . custom_build ,
988
- kind : unit. kind ,
989
- } )
990
- }
991
-
992
- fn maybe_lib ( & self , unit : & Unit < ' a > ) -> Option < Unit < ' a > > {
993
- unit. pkg
994
- . targets ( )
995
- . iter ( )
996
- . find ( |t| t. linkable ( ) )
997
- . map ( |t| Unit {
998
- pkg : unit. pkg ,
999
- target : t,
1000
- profile : self . lib_or_check_profile ( unit, t) ,
1001
- kind : unit. kind . for_target ( t) ,
1002
- } )
802
+ self . unit_dependencies . as_ref ( ) . unwrap ( ) [ unit] . clone ( )
1003
803
}
1004
804
1005
805
fn dep_platform_activated ( & self , dep : & Dependency , kind : Kind ) -> bool {
@@ -1066,15 +866,6 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
1066
866
}
1067
867
}
1068
868
1069
- pub fn lib_or_check_profile ( & self , unit : & Unit , target : & Target ) -> & ' a Profile {
1070
- if !target. is_custom_build ( ) && !target. for_host ( )
1071
- && ( unit. profile . check || ( unit. profile . doc && !unit. profile . test ) )
1072
- {
1073
- return & self . profiles . check ;
1074
- }
1075
- self . lib_profile ( )
1076
- }
1077
-
1078
869
pub fn build_script_profile ( & self , _pkg : & PackageId ) -> & ' a Profile {
1079
870
// TODO: should build scripts always be built with the same library
1080
871
// profile? How is this controlled at the CLI layer?
0 commit comments