11use 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 ;
34use crate :: core:: compiler:: job_queue:: JobState ;
45use crate :: core:: { profiles:: ProfileRoot , PackageId } ;
56use crate :: util:: errors:: { CargoResult , CargoResultExt } ;
@@ -41,37 +42,49 @@ pub struct BuildOutput {
4142/// This initially starts out as empty. Overridden build scripts get
4243/// inserted during `build_map`. The rest of the entries are added
4344/// 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+ }
4554
4655/// Linking information for a `Unit`.
4756///
4857/// See `build_map` for more details.
4958#[ derive( Default ) ]
5059pub struct BuildScripts {
60+ /// List of build script outputs this Unit needs to include for linking. Each
61+ /// element is an index into `BuildScriptOutputs`.
62+ ///
5163 /// Cargo will use this `to_link` vector to add `-L` flags to compiles as we
5264 /// propagate them upwards towards the final build. Note, however, that we
5365 /// need to preserve the ordering of `to_link` to be topologically sorted.
5466 /// This will ensure that build scripts which print their paths properly will
5567 /// correctly pick up the files they generated (if there are duplicates
5668 /// elsewhere).
5769 ///
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
5971 /// in the `Vec` and once in `seen_to_link` for a fast lookup. We maintain
6072 /// this as we're building interactively below to ensure that the memory
6173 /// usage here doesn't blow up too much.
6274 ///
6375 /// For more information, see #2354.
64- pub to_link : Vec < ( PackageId , CompileKind ) > ,
76+ pub to_link : Vec < ( PackageId , Metadata ) > ,
6577 /// 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`.
6881 ///
6982 /// This is the set of transitive dependencies that are host-only
7083 /// (proc-macro, plugin, build-dependency) that contain a build script.
7184 /// Any `BuildOutput::library_paths` path relative to `target` will be
7285 /// added to LD_LIBRARY_PATH so that the compiler can find any dynamic
7386 /// libraries a build script may have generated.
74- pub plugins : BTreeSet < PackageId > ,
87+ pub plugins : BTreeSet < ( PackageId , Metadata ) > ,
7588}
7689
7790/// 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
94107 unit. target. name( )
95108 ) ) ;
96109
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+ {
100117 // The output is already set, thus the build script is overridden.
101118 fingerprint:: prepare_target ( cx, unit, false )
102119 } else {
@@ -231,9 +248,11 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoRes
231248 . iter ( )
232249 . filter_map ( |dep| {
233250 if dep. unit . mode . is_run_custom_build ( ) {
251+ let dep_metadata = cx. get_run_build_script_metadata ( & dep. unit ) ;
234252 Some ( (
235253 dep. unit . pkg . manifest ( ) . links ( ) . unwrap ( ) . to_string ( ) ,
236254 dep. unit . pkg . package_id ( ) ,
255+ dep_metadata,
237256 ) )
238257 } else {
239258 None
@@ -255,10 +274,10 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoRes
255274 script_out_dir. clone ( ) ,
256275 ) ;
257276 let build_scripts = cx. build_scripts . get ( unit) . cloned ( ) ;
258- let kind = unit. kind ;
259277 let json_messages = bcx. build_config . emit_json ( ) ;
260278 let extra_verbose = bcx. config . extra_verbose ( ) ;
261279 let ( prev_output, prev_script_out_dir) = prev_build_output ( cx, unit) ;
280+ let metadata_hash = cx. get_run_build_script_metadata ( unit) ;
262281
263282 paths:: create_dir_all ( & script_dir) ?;
264283 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
286305 // native dynamic libraries.
287306 if !build_plan {
288307 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+ } ) ?;
298318 let data = & script_output. metadata ;
299319 for & ( ref key, ref value) in data. iter ( ) {
300320 cmd. env (
@@ -360,7 +380,7 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoRes
360380 build_script_outputs
361381 . lock ( )
362382 . unwrap ( )
363- . insert ( ( id, kind ) , parsed_output) ;
383+ . insert ( id, metadata_hash , parsed_output) ;
364384 Ok ( ( ) )
365385 } ) ;
366386
@@ -386,7 +406,7 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoRes
386406 build_script_outputs
387407 . lock ( )
388408 . unwrap ( )
389- . insert ( ( id, kind ) , output) ;
409+ . insert ( id, metadata_hash , output) ;
390410 Ok ( ( ) )
391411 } ) ;
392412
@@ -614,7 +634,7 @@ impl BuildDeps {
614634/// scripts.
615635///
616636/// 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
618638/// dependencies with build scripts that the unit should consider when
619639/// linking. For example this lists all dependencies' `-L` flags which need to
620640/// be propagated transitively.
@@ -644,20 +664,27 @@ pub fn build_map<'b, 'cfg>(cx: &mut Context<'b, 'cfg>, units: &[Unit<'b>]) -> Ca
644664 }
645665
646666 // 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+ }
654677 }
655678 }
656679
657680 let mut ret = BuildScripts :: default ( ) ;
658681
682+ // If a package has a build script, add itself as something to inspect for linking.
659683 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) ;
661688 }
662689
663690 // 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
676703 let dep_scripts = build ( out, cx, dep_unit) ?;
677704
678705 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 ( ) ) ;
681707 } 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 ) ;
684710 }
685711 }
686712 }
@@ -693,9 +719,9 @@ pub fn build_map<'b, 'cfg>(cx: &mut Context<'b, 'cfg>, units: &[Unit<'b>]) -> Ca
693719
694720 // When adding an entry to 'to_link' we only actually push it on if the
695721 // 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 ) ) ;
699725 }
700726 }
701727
@@ -741,3 +767,37 @@ fn prev_build_output<'a, 'cfg>(
741767 prev_script_out_dir,
742768 )
743769}
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