1
1
use super :: job:: { Freshness , Job , Work } ;
2
- use super :: { fingerprint, CompileKind , Context , Unit } ;
2
+ use super :: { fingerprint, Context , Unit } ;
3
+ use crate :: core:: compiler:: context:: Metadata ;
3
4
use crate :: core:: compiler:: job_queue:: JobState ;
4
5
use crate :: core:: { profiles:: ProfileRoot , PackageId } ;
5
6
use crate :: util:: errors:: { CargoResult , CargoResultExt } ;
@@ -41,37 +42,49 @@ pub struct BuildOutput {
41
42
/// This initially starts out as empty. Overridden build scripts get
42
43
/// inserted during `build_map`. The rest of the entries are added
43
44
/// immediately after each build script runs.
44
- pub type BuildScriptOutputs = HashMap < ( PackageId , CompileKind ) , BuildOutput > ;
45
+ ///
46
+ /// The `Metadata` is the unique metadata hash for the RunCustomBuild Unit of
47
+ /// the package. It needs a unique key, since the build script can be run
48
+ /// multiple times with different profiles or features. We can't embed a
49
+ /// `Unit` because this structure needs to be shareable between threads.
50
+ #[ derive( Default ) ]
51
+ pub struct BuildScriptOutputs {
52
+ outputs : HashMap < ( PackageId , Metadata ) , BuildOutput > ,
53
+ }
45
54
46
55
/// Linking information for a `Unit`.
47
56
///
48
57
/// See `build_map` for more details.
49
58
#[ derive( Default ) ]
50
59
pub struct BuildScripts {
60
+ /// List of build script outputs this Unit needs to include for linking. Each
61
+ /// element is an index into `BuildScriptOutputs`.
62
+ ///
51
63
/// Cargo will use this `to_link` vector to add `-L` flags to compiles as we
52
64
/// propagate them upwards towards the final build. Note, however, that we
53
65
/// need to preserve the ordering of `to_link` to be topologically sorted.
54
66
/// This will ensure that build scripts which print their paths properly will
55
67
/// correctly pick up the files they generated (if there are duplicates
56
68
/// elsewhere).
57
69
///
58
- /// To preserve this ordering, the (id, kind ) is stored in two places, once
70
+ /// To preserve this ordering, the (id, metadata ) is stored in two places, once
59
71
/// in the `Vec` and once in `seen_to_link` for a fast lookup. We maintain
60
72
/// this as we're building interactively below to ensure that the memory
61
73
/// usage here doesn't blow up too much.
62
74
///
63
75
/// For more information, see #2354.
64
- pub to_link : Vec < ( PackageId , CompileKind ) > ,
76
+ pub to_link : Vec < ( PackageId , Metadata ) > ,
65
77
/// This is only used while constructing `to_link` to avoid duplicates.
66
- seen_to_link : HashSet < ( PackageId , CompileKind ) > ,
67
- /// Host-only dependencies that have build scripts.
78
+ seen_to_link : HashSet < ( PackageId , Metadata ) > ,
79
+ /// Host-only dependencies that have build scripts. Each element is an
80
+ /// index into `BuildScriptOutputs`.
68
81
///
69
82
/// This is the set of transitive dependencies that are host-only
70
83
/// (proc-macro, plugin, build-dependency) that contain a build script.
71
84
/// Any `BuildOutput::library_paths` path relative to `target` will be
72
85
/// added to LD_LIBRARY_PATH so that the compiler can find any dynamic
73
86
/// libraries a build script may have generated.
74
- pub plugins : BTreeSet < PackageId > ,
87
+ pub plugins : BTreeSet < ( PackageId , Metadata ) > ,
75
88
}
76
89
77
90
/// Dependency information as declared by a build script.
@@ -94,9 +107,13 @@ pub fn prepare<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoRe
94
107
unit. target. name( )
95
108
) ) ;
96
109
97
- let key = ( unit. pkg . package_id ( ) , unit. kind ) ;
98
-
99
- if cx. build_script_outputs . lock ( ) . unwrap ( ) . contains_key ( & key) {
110
+ let metadata = cx. get_run_build_script_metadata ( unit) ;
111
+ if cx
112
+ . build_script_outputs
113
+ . lock ( )
114
+ . unwrap ( )
115
+ . contains_key ( unit. pkg . package_id ( ) , metadata)
116
+ {
100
117
// The output is already set, thus the build script is overridden.
101
118
fingerprint:: prepare_target ( cx, unit, false )
102
119
} else {
@@ -231,9 +248,11 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoRes
231
248
. iter ( )
232
249
. filter_map ( |dep| {
233
250
if dep. unit . mode . is_run_custom_build ( ) {
251
+ let dep_metadata = cx. get_run_build_script_metadata ( & dep. unit ) ;
234
252
Some ( (
235
253
dep. unit . pkg . manifest ( ) . links ( ) . unwrap ( ) . to_string ( ) ,
236
254
dep. unit . pkg . package_id ( ) ,
255
+ dep_metadata,
237
256
) )
238
257
} else {
239
258
None
@@ -255,10 +274,10 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoRes
255
274
script_out_dir. clone ( ) ,
256
275
) ;
257
276
let build_scripts = cx. build_scripts . get ( unit) . cloned ( ) ;
258
- let kind = unit. kind ;
259
277
let json_messages = bcx. build_config . emit_json ( ) ;
260
278
let extra_verbose = bcx. config . extra_verbose ( ) ;
261
279
let ( prev_output, prev_script_out_dir) = prev_build_output ( cx, unit) ;
280
+ let metadata_hash = cx. get_run_build_script_metadata ( unit) ;
262
281
263
282
paths:: create_dir_all ( & script_dir) ?;
264
283
paths:: create_dir_all ( & script_out_dir) ?;
@@ -286,15 +305,16 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoRes
286
305
// native dynamic libraries.
287
306
if !build_plan {
288
307
let build_script_outputs = build_script_outputs. lock ( ) . unwrap ( ) ;
289
- for ( name, id) in lib_deps {
290
- let key = ( id, kind) ;
291
- let script_output = build_script_outputs. get ( & key) . ok_or_else ( || {
292
- internal ( format ! (
293
- "failed to locate build state for env \
294
- vars: {}/{:?}",
295
- id, kind
296
- ) )
297
- } ) ?;
308
+ for ( name, dep_id, dep_metadata) in lib_deps {
309
+ let script_output =
310
+ build_script_outputs
311
+ . get ( dep_id, dep_metadata)
312
+ . ok_or_else ( || {
313
+ internal ( format ! (
314
+ "failed to locate build state for env vars: {}/{}" ,
315
+ dep_id, dep_metadata
316
+ ) )
317
+ } ) ?;
298
318
let data = & script_output. metadata ;
299
319
for & ( ref key, ref value) in data. iter ( ) {
300
320
cmd. env (
@@ -360,7 +380,7 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoRes
360
380
build_script_outputs
361
381
. lock ( )
362
382
. unwrap ( )
363
- . insert ( ( id, kind ) , parsed_output) ;
383
+ . insert ( id, metadata_hash , parsed_output) ;
364
384
Ok ( ( ) )
365
385
} ) ;
366
386
@@ -386,7 +406,7 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoRes
386
406
build_script_outputs
387
407
. lock ( )
388
408
. unwrap ( )
389
- . insert ( ( id, kind ) , output) ;
409
+ . insert ( id, metadata_hash , output) ;
390
410
Ok ( ( ) )
391
411
} ) ;
392
412
@@ -614,7 +634,7 @@ impl BuildDeps {
614
634
/// scripts.
615
635
///
616
636
/// The important one here is `build_scripts`, which for each `(package,
617
- /// kind )` stores a `BuildScripts` object which contains a list of
637
+ /// metadata )` stores a `BuildScripts` object which contains a list of
618
638
/// dependencies with build scripts that the unit should consider when
619
639
/// linking. For example this lists all dependencies' `-L` flags which need to
620
640
/// be propagated transitively.
@@ -644,20 +664,27 @@ pub fn build_map<'b, 'cfg>(cx: &mut Context<'b, 'cfg>, units: &[Unit<'b>]) -> Ca
644
664
}
645
665
646
666
// If there is a build script override, pre-fill the build output.
647
- if let Some ( links) = unit. pkg . manifest ( ) . links ( ) {
648
- if let Some ( output) = cx. bcx . script_override ( links, unit. kind ) {
649
- let key = ( unit. pkg . package_id ( ) , unit. kind ) ;
650
- cx. build_script_outputs
651
- . lock ( )
652
- . unwrap ( )
653
- . insert ( key, output. clone ( ) ) ;
667
+ if unit. mode . is_run_custom_build ( ) {
668
+ if let Some ( links) = unit. pkg . manifest ( ) . links ( ) {
669
+ if let Some ( output) = cx. bcx . script_override ( links, unit. kind ) {
670
+ let metadata = cx. get_run_build_script_metadata ( unit) ;
671
+ cx. build_script_outputs . lock ( ) . unwrap ( ) . insert (
672
+ unit. pkg . package_id ( ) ,
673
+ metadata,
674
+ output. clone ( ) ,
675
+ ) ;
676
+ }
654
677
}
655
678
}
656
679
657
680
let mut ret = BuildScripts :: default ( ) ;
658
681
682
+ // If a package has a build script, add itself as something to inspect for linking.
659
683
if !unit. target . is_custom_build ( ) && unit. pkg . has_custom_build ( ) {
660
- add_to_link ( & mut ret, unit. pkg . package_id ( ) , unit. kind ) ;
684
+ let script_meta = cx
685
+ . find_build_script_metadata ( * unit)
686
+ . expect ( "has_custom_build should have RunCustomBuild" ) ;
687
+ add_to_link ( & mut ret, unit. pkg . package_id ( ) , script_meta) ;
661
688
}
662
689
663
690
// Load any dependency declarations from a previous run.
@@ -676,11 +703,10 @@ pub fn build_map<'b, 'cfg>(cx: &mut Context<'b, 'cfg>, units: &[Unit<'b>]) -> Ca
676
703
let dep_scripts = build ( out, cx, dep_unit) ?;
677
704
678
705
if dep_unit. target . for_host ( ) {
679
- ret. plugins
680
- . extend ( dep_scripts. to_link . iter ( ) . map ( |p| & p. 0 ) . cloned ( ) ) ;
706
+ ret. plugins . extend ( dep_scripts. to_link . iter ( ) . cloned ( ) ) ;
681
707
} else if dep_unit. target . linkable ( ) {
682
- for & ( pkg, kind ) in dep_scripts. to_link . iter ( ) {
683
- add_to_link ( & mut ret, pkg, kind ) ;
708
+ for & ( pkg, metadata ) in dep_scripts. to_link . iter ( ) {
709
+ add_to_link ( & mut ret, pkg, metadata ) ;
684
710
}
685
711
}
686
712
}
@@ -693,9 +719,9 @@ pub fn build_map<'b, 'cfg>(cx: &mut Context<'b, 'cfg>, units: &[Unit<'b>]) -> Ca
693
719
694
720
// When adding an entry to 'to_link' we only actually push it on if the
695
721
// script hasn't seen it yet (e.g., we don't push on duplicates).
696
- fn add_to_link ( scripts : & mut BuildScripts , pkg : PackageId , kind : CompileKind ) {
697
- if scripts. seen_to_link . insert ( ( pkg, kind ) ) {
698
- scripts. to_link . push ( ( pkg, kind ) ) ;
722
+ fn add_to_link ( scripts : & mut BuildScripts , pkg : PackageId , metadata : Metadata ) {
723
+ if scripts. seen_to_link . insert ( ( pkg, metadata ) ) {
724
+ scripts. to_link . push ( ( pkg, metadata ) ) ;
699
725
}
700
726
}
701
727
@@ -741,3 +767,37 @@ fn prev_build_output<'a, 'cfg>(
741
767
prev_script_out_dir,
742
768
)
743
769
}
770
+
771
+ impl BuildScriptOutputs {
772
+ /// Inserts a new entry into the map.
773
+ fn insert ( & mut self , pkg_id : PackageId , metadata : Metadata , parsed_output : BuildOutput ) {
774
+ match self . outputs . entry ( ( pkg_id, metadata) ) {
775
+ Entry :: Vacant ( entry) => {
776
+ entry. insert ( parsed_output) ;
777
+ }
778
+ Entry :: Occupied ( entry) => panic ! (
779
+ "build script output collision for {}/{}\n \
780
+ old={:?}\n new={:?}",
781
+ pkg_id,
782
+ metadata,
783
+ entry. get( ) ,
784
+ parsed_output
785
+ ) ,
786
+ }
787
+ }
788
+
789
+ /// Returns `true` if the given key already exists.
790
+ fn contains_key ( & self , pkg_id : PackageId , metadata : Metadata ) -> bool {
791
+ self . outputs . contains_key ( & ( pkg_id, metadata) )
792
+ }
793
+
794
+ /// Gets the build output for the given key.
795
+ pub fn get ( & self , pkg_id : PackageId , meta : Metadata ) -> Option < & BuildOutput > {
796
+ self . outputs . get ( & ( pkg_id, meta) )
797
+ }
798
+
799
+ /// Returns an iterator over all entries.
800
+ pub fn iter ( & self ) -> impl Iterator < Item = ( PackageId , & BuildOutput ) > {
801
+ self . outputs . iter ( ) . map ( |( key, value) | ( key. 0 , value) )
802
+ }
803
+ }
0 commit comments