@@ -33,7 +33,7 @@ use std::sync::mpsc::Sender;
33
33
34
34
use crate :: build:: PackageArg ;
35
35
use cargo:: core:: { PackageId , Target , TargetKind } ;
36
- use cargo:: core:: compiler:: { Context , Kind , Unit } ;
36
+ use cargo:: core:: compiler:: { CompileMode , Context , Kind , Unit } ;
37
37
use cargo:: core:: profiles:: Profile ;
38
38
use cargo:: util:: { CargoResult , ProcessBuilder } ;
39
39
use cargo_metadata;
@@ -45,7 +45,9 @@ use crate::actions::progress::ProgressUpdate;
45
45
use super :: { BuildResult , Internals } ;
46
46
47
47
/// Main key type by which `Unit`s will be distinguished in the build plan.
48
- crate type UnitKey = ( PackageId , TargetKind ) ;
48
+ /// In Target we're mostly interested in TargetKind (Lib, Bin, ...) and name
49
+ /// (e.g. we can have 2 binary targets with different names).
50
+ crate type UnitKey = ( PackageId , Target , CompileMode ) ;
49
51
50
52
/// Holds the information how exactly the build will be performed for a given
51
53
/// workspace with given, specified features.
@@ -91,8 +93,8 @@ impl Plan {
91
93
/// Cache a given compiler invocation in `ProcessBuilder` for a given
92
94
/// `PackageId` and `TargetKind` in `Target`, to be used when processing
93
95
/// cached build plan.
94
- crate fn cache_compiler_job ( & mut self , id : & PackageId , target : & Target , cmd : & ProcessBuilder ) {
95
- let pkg_key = ( id. clone ( ) , target. kind ( ) . clone ( ) ) ;
96
+ crate fn cache_compiler_job ( & mut self , id : & PackageId , target : & Target , mode : CompileMode , cmd : & ProcessBuilder ) {
97
+ let pkg_key = ( id. clone ( ) , target. clone ( ) , mode ) ;
96
98
self . compiler_jobs . insert ( pkg_key, cmd. clone ( ) ) ;
97
99
}
98
100
@@ -176,12 +178,12 @@ impl Plan {
176
178
177
179
let build_scripts: HashMap < & Path , UnitKey > = self . units
178
180
. iter ( )
179
- . filter ( |& ( & ( _, ref kind ) , _) | * kind == TargetKind :: CustomBuild )
181
+ . filter ( |& ( & ( _, ref target , _ ) , _) | * target . kind ( ) == TargetKind :: CustomBuild )
180
182
. map ( |( key, unit) | ( unit. target . src_path ( ) , key. clone ( ) ) )
181
183
. collect ( ) ;
182
184
let other_targets: HashMap < UnitKey , & Path > = self . units
183
185
. iter ( )
184
- . filter ( |& ( & ( _, ref kind ) , _) | * kind != TargetKind :: CustomBuild )
186
+ . filter ( |& ( & ( _, ref target , _ ) , _) | * target . kind ( ) != TargetKind :: CustomBuild )
185
187
. map ( |( key, unit) | {
186
188
(
187
189
key. clone ( ) ,
@@ -197,27 +199,32 @@ impl Plan {
197
199
if let Some ( unit) = build_scripts. get ( modified) {
198
200
result. insert ( unit. clone ( ) ) ;
199
201
} else {
200
- // Not a build script, so we associate a dirty package with a
201
- // dirty file by finding longest (most specified) path prefix
202
- let unit = other_targets. iter ( ) . max_by_key ( |& ( _, src_dir) | {
203
- if !modified. starts_with ( src_dir) {
204
- return 0 ;
205
- }
206
- modified
207
- . components ( )
208
- . zip ( src_dir. components ( ) )
209
- . take_while ( |& ( a, b) | a == b)
202
+ // Not a build script, so we associate a dirty file with a
203
+ // package by finding longest (most specified) path prefix.
204
+ let matching_prefix_components = |a : & Path , b : & Path | -> usize {
205
+ assert ! ( a. is_absolute( ) && b. is_absolute( ) ) ;
206
+ a. components ( ) . zip ( b. components ( ) )
207
+ . skip ( 1 ) // Skip RootDir
208
+ . take_while ( |& ( x, y) | x == y)
210
209
. count ( )
211
- } ) ;
212
- match unit {
213
- None => trace ! (
214
- "Modified file {:?} doesn't correspond to any package!" ,
215
- modified. display( )
216
- ) ,
217
- Some ( unit) => {
218
- result. insert ( unit. 0 . clone ( ) ) ;
219
- }
220
210
} ;
211
+ // Since a package can correspond to many units (e.g. compiled
212
+ // as a regular binary or a test harness for unit tests), we
213
+ // collect every unit having the longest path prefix.
214
+ let max_matching_prefix = other_targets. values ( )
215
+ . map ( |src_dir| matching_prefix_components ( modified, src_dir) )
216
+ . max ( ) . unwrap ( ) ;
217
+
218
+ if max_matching_prefix == 0 {
219
+ trace ! ( "Modified file didn't correspond to any buildable unit!" ) ;
220
+ } else {
221
+ let dirty_units = other_targets. iter ( )
222
+ . filter ( |( _, src_dir) | max_matching_prefix ==
223
+ matching_prefix_components ( modified, src_dir)
224
+ ) . map ( |( unit, _) | unit) ;
225
+
226
+ result. extend ( dirty_units. cloned ( ) ) ;
227
+ }
221
228
}
222
229
}
223
230
result
@@ -344,7 +351,7 @@ impl Plan {
344
351
345
352
if dirties
346
353
. iter ( )
347
- . any ( |& ( _, ref kind ) | * kind == TargetKind :: CustomBuild )
354
+ . any ( |& ( _, ref target , _ ) | * target . kind ( ) == TargetKind :: CustomBuild )
348
355
{
349
356
WorkStatus :: NeedsCargo ( PackageArg :: Packages ( needed_packages) )
350
357
} else {
@@ -594,7 +601,7 @@ impl JobQueue {
594
601
}
595
602
596
603
fn key_from_unit ( unit : & Unit < ' _ > ) -> UnitKey {
597
- ( unit. pkg . package_id ( ) . clone ( ) , unit. target . kind ( ) . clone ( ) )
604
+ ( unit. pkg . package_id ( ) . clone ( ) , unit. target . clone ( ) , unit . mode )
598
605
}
599
606
600
607
macro_rules! print_dep_graph {
@@ -626,6 +633,7 @@ crate struct OwnedUnit {
626
633
crate target : Target ,
627
634
crate profile : Profile ,
628
635
crate kind : Kind ,
636
+ crate mode : CompileMode ,
629
637
}
630
638
631
639
impl < ' a > From < & ' a Unit < ' a > > for OwnedUnit {
@@ -635,6 +643,7 @@ impl<'a> From<&'a Unit<'a>> for OwnedUnit {
635
643
target : unit. target . clone ( ) ,
636
644
profile : unit. profile ,
637
645
kind : unit. kind ,
646
+ mode : unit. mode ,
638
647
}
639
648
}
640
649
}
0 commit comments