@@ -16,6 +16,7 @@ use la_arena::ArenaMap;
1616use paths:: { AbsPath , AbsPathBuf , Utf8PathBuf } ;
1717use rustc_hash:: { FxHashMap , FxHashSet } ;
1818use serde:: Deserialize as _;
19+ use stdx:: { always, never} ;
1920use toolchain:: Tool ;
2021
2122use crate :: {
@@ -30,6 +31,15 @@ pub struct WorkspaceBuildScripts {
3031 error : Option < String > ,
3132}
3233
34+ #[ derive( Debug , Clone , Default , PartialEq , Eq ) ]
35+ pub enum ProcMacroDylibPath {
36+ Path ( AbsPathBuf ) ,
37+ DylibNotFound ( Box < [ Utf8PathBuf ] > ) ,
38+ NotProcMacro ,
39+ #[ default]
40+ NotBuilt ,
41+ }
42+
3343/// Output of the build script and proc-macro building step for a concrete package.
3444#[ derive( Debug , Clone , Default , PartialEq , Eq ) ]
3545pub ( crate ) struct BuildScriptOutput {
@@ -43,15 +53,15 @@ pub(crate) struct BuildScriptOutput {
4353 /// Directory where a build script might place its output.
4454 pub ( crate ) out_dir : Option < AbsPathBuf > ,
4555 /// Path to the proc-macro library file if this package exposes proc-macros.
46- pub ( crate ) proc_macro_dylib_path : Option < AbsPathBuf > ,
56+ pub ( crate ) proc_macro_dylib_path : ProcMacroDylibPath ,
4757}
4858
4959impl BuildScriptOutput {
5060 fn is_empty ( & self ) -> bool {
5161 self . cfgs . is_empty ( )
5262 && self . envs . is_empty ( )
5363 && self . out_dir . is_none ( )
54- && self . proc_macro_dylib_path . is_none ( )
64+ && self . proc_macro_dylib_path == ProcMacroDylibPath :: NotBuilt
5565 }
5666}
5767
@@ -126,6 +136,8 @@ impl WorkspaceBuildScripts {
126136 |package, cb| {
127137 if let Some ( & ( package, workspace) ) = by_id. get ( package) {
128138 cb ( & workspaces[ workspace] [ package] . name , & mut res[ workspace] . outputs [ package] ) ;
139+ } else {
140+ never ! ( "Received compiler message for unknown package: {}" , package) ;
129141 }
130142 } ,
131143 progress,
@@ -140,12 +152,9 @@ impl WorkspaceBuildScripts {
140152 if tracing:: enabled!( tracing:: Level :: INFO ) {
141153 for ( idx, workspace) in workspaces. iter ( ) . enumerate ( ) {
142154 for package in workspace. packages ( ) {
143- let package_build_data = & mut res[ idx] . outputs [ package] ;
155+ let package_build_data: & mut BuildScriptOutput = & mut res[ idx] . outputs [ package] ;
144156 if !package_build_data. is_empty ( ) {
145- tracing:: info!(
146- "{}: {package_build_data:?}" ,
147- workspace[ package] . manifest. parent( ) ,
148- ) ;
157+ tracing:: info!( "{}: {package_build_data:?}" , workspace[ package] . manifest, ) ;
149158 }
150159 }
151160 }
@@ -198,39 +207,58 @@ impl WorkspaceBuildScripts {
198207 let path = dir_entry. path ( ) ;
199208 let extension = path. extension ( ) ?;
200209 if extension == std:: env:: consts:: DLL_EXTENSION {
201- let name = path. file_stem ( ) ?. to_str ( ) ?. split_once ( '-' ) ?. 0 . to_owned ( ) ;
202- let path = AbsPathBuf :: try_from ( Utf8PathBuf :: from_path_buf ( path) . ok ( ) ?)
203- . ok ( ) ?;
204- return Some ( ( name, path) ) ;
210+ let name = path
211+ . file_stem ( ) ?
212+ . to_str ( ) ?
213+ . split_once ( '-' ) ?
214+ . 0
215+ . trim_start_matches ( "lib" )
216+ . to_owned ( ) ;
217+ let path = match Utf8PathBuf :: from_path_buf ( path) {
218+ Ok ( path) => path,
219+ Err ( path) => {
220+ tracing:: warn!(
221+ "Proc-macro dylib path contains non-UTF8 characters: {:?}" ,
222+ path. display( )
223+ ) ;
224+ return None ;
225+ }
226+ } ;
227+ return match AbsPathBuf :: try_from ( path) {
228+ Ok ( path) => Some ( ( name, path) ) ,
229+ Err ( path) => {
230+ tracing:: error!(
231+ "proc-macro dylib path is not absolute: {:?}" ,
232+ path
233+ ) ;
234+ None
235+ }
236+ } ;
205237 }
206238 }
207239 None
208240 } )
209241 . collect ( ) ;
210242 for p in rustc. packages ( ) {
211243 let package = & rustc[ p] ;
212- if package
213- . targets
214- . iter ( )
215- . any ( | & it| matches ! ( rustc [ it ] . kind , TargetKind :: Lib { is_proc_macro : true } ) )
216- {
217- if let Some ( ( _, path) ) = proc_macro_dylibs
218- . iter ( )
219- . find ( | ( name , _ ) | * name . trim_start_matches ( "lib" ) == package . name )
220- {
221- bs . outputs [ p ] . proc_macro_dylib_path = Some ( path . clone ( ) ) ;
244+ bs . outputs [ p ] . proc_macro_dylib_path =
245+ if package . targets . iter ( ) . any ( | & it| {
246+ matches ! ( rustc [ it ] . kind , TargetKind :: Lib { is_proc_macro : true } )
247+ } ) {
248+ match proc_macro_dylibs . iter ( ) . find ( | ( name , _ ) | * name == package . name ) {
249+ Some ( ( _, path) ) => ProcMacroDylibPath :: Path ( path . clone ( ) ) ,
250+ _ => ProcMacroDylibPath :: DylibNotFound ( Box :: default ( ) ) ,
251+ }
252+ } else {
253+ ProcMacroDylibPath :: NotProcMacro
222254 }
223- }
224255 }
225256
226257 if tracing:: enabled!( tracing:: Level :: INFO ) {
227258 for package in rustc. packages ( ) {
228259 let package_build_data = & bs. outputs [ package] ;
229260 if !package_build_data. is_empty ( ) {
230- tracing:: info!(
231- "{}: {package_build_data:?}" ,
232- rustc[ package] . manifest. parent( ) ,
233- ) ;
261+ tracing:: info!( "{}: {package_build_data:?}" , rustc[ package] . manifest, ) ;
234262 }
235263 }
236264 }
@@ -263,6 +291,12 @@ impl WorkspaceBuildScripts {
263291 |package, cb| {
264292 if let Some ( & package) = by_id. get ( package) {
265293 cb ( & workspace[ package] . name , & mut outputs[ package] ) ;
294+ } else {
295+ never ! (
296+ "Received compiler message for unknown package: {}\n {}" ,
297+ package,
298+ by_id. keys( ) . join( ", " )
299+ ) ;
266300 }
267301 } ,
268302 progress,
@@ -272,10 +306,7 @@ impl WorkspaceBuildScripts {
272306 for package in workspace. packages ( ) {
273307 let package_build_data = & outputs[ package] ;
274308 if !package_build_data. is_empty ( ) {
275- tracing:: info!(
276- "{}: {package_build_data:?}" ,
277- workspace[ package] . manifest. parent( ) ,
278- ) ;
309+ tracing:: info!( "{}: {package_build_data:?}" , workspace[ package] . manifest, ) ;
279310 }
280311 }
281312 }
@@ -348,15 +379,25 @@ impl WorkspaceBuildScripts {
348379 progress ( format ! (
349380 "building compile-time-deps: proc-macro {name} built"
350381 ) ) ;
382+ always ! (
383+ data. proc_macro_dylib_path == ProcMacroDylibPath :: NotBuilt ,
384+ "received multiple compiler artifacts for the same package: {message:?}"
385+ ) ;
386+ if data. proc_macro_dylib_path == ProcMacroDylibPath :: NotBuilt {
387+ data. proc_macro_dylib_path = ProcMacroDylibPath :: NotProcMacro ;
388+ }
351389 if message. target . kind . contains ( & cargo_metadata:: TargetKind :: ProcMacro )
352390 {
353- // Skip rmeta file
354- if let Some ( filename) =
355- message. filenames . iter ( ) . find ( |file| is_dylib ( file) )
356- {
357- let filename = AbsPath :: assert ( filename) ;
358- data. proc_macro_dylib_path = Some ( filename. to_owned ( ) ) ;
359- }
391+ data. proc_macro_dylib_path =
392+ match message. filenames . iter ( ) . find ( |file| is_dylib ( file) ) {
393+ Some ( filename) => {
394+ let filename = AbsPath :: assert ( filename) ;
395+ ProcMacroDylibPath :: Path ( filename. to_owned ( ) )
396+ }
397+ None => ProcMacroDylibPath :: DylibNotFound (
398+ message. filenames . clone ( ) . into_boxed_slice ( ) ,
399+ ) ,
400+ } ;
360401 }
361402 } ) ;
362403 }
0 commit comments